From 80809dee6f6d120234c4570056c9a10c063953d8 Mon Sep 17 00:00:00 2001 From: acspike Date: Mon, 8 May 2006 15:28:17 +0000 Subject: [PATCH] standardize indents on 4 spaces Python hates mixed whitespace --- share/extensions/addnodes.py | 118 ++-- share/extensions/bezmisc.py | 314 +++++------ share/extensions/cspsubdiv.py | 57 +- share/extensions/cubicsuperpath.py | 98 ++-- share/extensions/dots.py | 96 ++-- share/extensions/dxf_outlines.py | 28 +- share/extensions/embedimage.py | 70 +-- share/extensions/eqtexsvg.py | 156 ++--- share/extensions/extractimage.py | 50 +- share/extensions/ffgeom.py | 208 +++---- share/extensions/ffproc.py | 332 +++++------ share/extensions/ffscale.py | 88 +-- share/extensions/flatten.py | 46 +- share/extensions/fretfind.py | 306 +++++----- share/extensions/gimp_xcf.py | 70 +-- share/extensions/handles.py | 62 +- share/extensions/interp.py | 564 +++++++++---------- share/extensions/kochify.py | 118 ++-- share/extensions/kochify_load.py | 68 +-- share/extensions/lindenmayer.py | 128 ++--- share/extensions/measure.py | 136 ++--- share/extensions/motion.py | 173 +++--- share/extensions/pturtle.py | 120 ++-- share/extensions/radiusrand.py | 90 +-- share/extensions/rtree.py | 66 +-- share/extensions/simplepath.py | 316 +++++------ share/extensions/simplestyle.py | 8 +- share/extensions/straightseg.py | 86 +-- share/extensions/summersnight.py | 124 ++-- share/extensions/svg_and_media_zip_output.py | 162 +++--- share/extensions/wavy.py | 186 +++--- share/extensions/whirl.py | 82 +-- 32 files changed, 2261 insertions(+), 2265 deletions(-) diff --git a/share/extensions/addnodes.py b/share/extensions/addnodes.py index d9814e066..e57c7566d 100644 --- a/share/extensions/addnodes.py +++ b/share/extensions/addnodes.py @@ -19,74 +19,74 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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() diff --git a/share/extensions/bezmisc.py b/share/extensions/bezmisc.py index 7efafa3ea..e8cc8c2e9 100755 --- a/share/extensions/bezmisc.py +++ b/share/extensions/bezmisc.py @@ -21,8 +21,8 @@ import math, cmath 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 @@ -35,39 +35,39 @@ def rootWrapper(a,b,c,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 @@ -147,104 +147,104 @@ mat-report no. 1992-10, Mathematical Institute, The Technical 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) diff --git a/share/extensions/cspsubdiv.py b/share/extensions/cspsubdiv.py index acf873ae1..427e7a494 100644 --- a/share/extensions/cspsubdiv.py +++ b/share/extensions/cspsubdiv.py @@ -3,37 +3,36 @@ from bezmisc import * 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 diff --git a/share/extensions/cubicsuperpath.py b/share/extensions/cubicsuperpath.py index fdd1afc59..0f34ec841 100755 --- a/share/extensions/cubicsuperpath.py +++ b/share/extensions/cubicsuperpath.py @@ -22,61 +22,61 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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)) diff --git a/share/extensions/dots.py b/share/extensions/dots.py index 2e24ef2b1..c5f6e8149 100755 --- a/share/extensions/dots.py +++ b/share/extensions/dots.py @@ -19,57 +19,57 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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() diff --git a/share/extensions/dxf_outlines.py b/share/extensions/dxf_outlines.py index 01e7b0633..176412ea3 100755 --- a/share/extensions/dxf_outlines.py +++ b/share/extensions/dxf_outlines.py @@ -20,21 +20,21 @@ import inkex, simplepath, cubicsuperpath, re 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 MyEffect(inkex.Effect): def __init__(self): diff --git a/share/extensions/embedimage.py b/share/extensions/embedimage.py index 12a0b78b2..b01407198 100644 --- a/share/extensions/embedimage.py +++ b/share/extensions/embedimage.py @@ -20,41 +20,41 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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() diff --git a/share/extensions/eqtexsvg.py b/share/extensions/eqtexsvg.py index 8828c8b6a..4232268af 100644 --- a/share/extensions/eqtexsvg.py +++ b/share/extensions/eqtexsvg.py @@ -30,92 +30,92 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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 "" "" "" 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() + + # 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 "" "" "" from svg_lines + nodegroup='' + s_nodegroup_path='' - for i in range(1,len(svg_lines)): - if svg_lines[i].find("") - nodegroup=nodegroup[0]+'\n' - elif svg_lines[i].find("") != -1: - s_nodegroup_path=s_nodegroup_path+'"\n' - elif svg_lines[i].find("") != -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("") + nodegroup=nodegroup[0]+'\n' + elif svg_lines[i].find("") != -1: + s_nodegroup_path=s_nodegroup_path+'"\n' + elif svg_lines[i].find("") != -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() diff --git a/share/extensions/extractimage.py b/share/extensions/extractimage.py index 27936bf80..f1b0f6f7a 100644 --- a/share/extensions/extractimage.py +++ b/share/extensions/extractimage.py @@ -20,31 +20,31 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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() diff --git a/share/extensions/ffgeom.py b/share/extensions/ffgeom.py index ab2c74b74..24d80a175 100755 --- a/share/extensions/ffgeom.py +++ b/share/extensions/ffgeom.py @@ -21,118 +21,118 @@ """ 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() diff --git a/share/extensions/ffproc.py b/share/extensions/ffproc.py index e5c726ced..b288d250d 100755 --- a/share/extensions/ffproc.py +++ b/share/extensions/ffproc.py @@ -23,172 +23,172 @@ from ffgeom import * 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 diff --git a/share/extensions/ffscale.py b/share/extensions/ffscale.py index f9afa0b02..74bc6b989 100755 --- a/share/extensions/ffscale.py +++ b/share/extensions/ffscale.py @@ -21,53 +21,53 @@ 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 diff --git a/share/extensions/flatten.py b/share/extensions/flatten.py index b33591e04..8dc4e393b 100755 --- a/share/extensions/flatten.py +++ b/share/extensions/flatten.py @@ -19,28 +19,28 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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 diff --git a/share/extensions/fretfind.py b/share/extensions/fretfind.py index 310a09a5d..a2ce6c961 100755 --- a/share/extensions/fretfind.py +++ b/share/extensions/fretfind.py @@ -21,166 +21,166 @@ import inkex, simplestyle, simplepath 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 diff --git a/share/extensions/gimp_xcf.py b/share/extensions/gimp_xcf.py index 936186d24..f295641f3 100755 --- a/share/extensions/gimp_xcf.py +++ b/share/extensions/gimp_xcf.py @@ -20,34 +20,34 @@ import inkex 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* @@ -77,16 +77,16 @@ class MyEffect(inkex.Effect): (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 diff --git a/share/extensions/handles.py b/share/extensions/handles.py index a77b84ccc..5ce41b734 100755 --- a/share/extensions/handles.py +++ b/share/extensions/handles.py @@ -19,38 +19,38 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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() diff --git a/share/extensions/interp.py b/share/extensions/interp.py index 5edbf026d..7e5407e6a 100755 --- a/share/extensions/interp.py +++ b/share/extensions/interp.py @@ -20,313 +20,313 @@ import inkex, cubicsuperpath, simplestyle, copy, math, re, bezmisc 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() diff --git a/share/extensions/kochify.py b/share/extensions/kochify.py index e6914278c..7f676cb98 100755 --- a/share/extensions/kochify.py +++ b/share/extensions/kochify.py @@ -19,68 +19,68 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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() diff --git a/share/extensions/kochify_load.py b/share/extensions/kochify_load.py index d50c498c0..9c178e3c4 100755 --- a/share/extensions/kochify_load.py +++ b/share/extensions/kochify_load.py @@ -19,42 +19,42 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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() diff --git a/share/extensions/lindenmayer.py b/share/extensions/lindenmayer.py index a6848320d..34c52bd98 100755 --- a/share/extensions/lindenmayer.py +++ b/share/extensions/lindenmayer.py @@ -19,70 +19,70 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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() diff --git a/share/extensions/measure.py b/share/extensions/measure.py index e8089ca05..690b8658f 100644 --- a/share/extensions/measure.py +++ b/share/extensions/measure.py @@ -20,87 +20,87 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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() diff --git a/share/extensions/motion.py b/share/extensions/motion.py index 95100e629..3834c7f2b 100755 --- a/share/extensions/motion.py +++ b/share/extensions/motion.py @@ -19,101 +19,98 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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= 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 diff --git a/share/extensions/simplestyle.py b/share/extensions/simplestyle.py index 32fd987b7..22b4c3e8b 100755 --- a/share/extensions/simplestyle.py +++ b/share/extensions/simplestyle.py @@ -20,8 +20,8 @@ along with this program; if not, write to the Free Software 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()]) diff --git a/share/extensions/straightseg.py b/share/extensions/straightseg.py index 692160e4d..dcec88e2c 100755 --- a/share/extensions/straightseg.py +++ b/share/extensions/straightseg.py @@ -19,51 +19,51 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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() diff --git a/share/extensions/summersnight.py b/share/extensions/summersnight.py index 7ddfdf275..6f39170eb 100755 --- a/share/extensions/summersnight.py +++ b/share/extensions/summersnight.py @@ -22,78 +22,78 @@ from ffgeom import * 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 09ecb5f99..93bf2ebad 100644 --- a/share/extensions/svg_and_media_zip_output.py +++ b/share/extensions/svg_and_media_zip_output.py @@ -26,9 +26,9 @@ Version 0.3 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 """ @@ -41,83 +41,83 @@ import sys 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() diff --git a/share/extensions/wavy.py b/share/extensions/wavy.py index aa438e121..c74e7d71e 100755 --- a/share/extensions/wavy.py +++ b/share/extensions/wavy.py @@ -33,101 +33,101 @@ from math import * 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() diff --git a/share/extensions/whirl.py b/share/extensions/whirl.py index 4b234d014..b20141917 100644 --- a/share/extensions/whirl.py +++ b/share/extensions/whirl.py @@ -19,47 +19,47 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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() -- 2.30.2