Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
d45d5617b6
12 files changed
-886039
No files matched your search
-274
@@ -1,274 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
'''
|
||||
Copyright (C) 2010 Nick Drobchenko, nick@cnc-club.ru
|
||||
Copyright (C) 2005 Aaron Spike, aaron@ekips.org
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
'''
|
||||
|
||||
import math, cmath
|
||||
|
||||
def rootWrapper(a,b,c,d):
|
||||
if a:
|
||||
# Monics formula see http://en.wikipedia.org/wiki/Cubic_function#Monic_formula_of_roots
|
||||
a,b,c = (b/a, c/a, d/a)
|
||||
m = 2.0*a**3 - 9.0*a*b + 27.0*c
|
||||
k = a**2 - 3.0*b
|
||||
n = m**2 - 4.0*k**3
|
||||
w1 = -.5 + .5*cmath.sqrt(-3.0)
|
||||
w2 = -.5 - .5*cmath.sqrt(-3.0)
|
||||
if n < 0:
|
||||
m1 = pow(complex((m+cmath.sqrt(n))/2),1./3)
|
||||
n1 = pow(complex((m-cmath.sqrt(n))/2),1./3)
|
||||
else:
|
||||
if m+math.sqrt(n) < 0:
|
||||
m1 = -pow(-(m+math.sqrt(n))/2,1./3)
|
||||
else:
|
||||
m1 = pow((m+math.sqrt(n))/2,1./3)
|
||||
if m-math.sqrt(n) < 0:
|
||||
n1 = -pow(-(m-math.sqrt(n))/2,1./3)
|
||||
else:
|
||||
n1 = pow((m-math.sqrt(n))/2,1./3)
|
||||
x1 = -1./3 * (a + m1 + n1)
|
||||
x2 = -1./3 * (a + w1*m1 + w2*n1)
|
||||
x3 = -1./3 * (a + w2*m1 + w1*n1)
|
||||
return (x1,x2,x3)
|
||||
elif b:
|
||||
det=c**2.0-4.0*b*d
|
||||
if det:
|
||||
return (-c+cmath.sqrt(det))/(2.0*b),(-c-cmath.sqrt(det))/(2.0*b)
|
||||
else:
|
||||
return -c/(2.0*b),
|
||||
elif c:
|
||||
return 1.0*(-d/c),
|
||||
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)))
|
||||
|
||||
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)
|
||||
|
||||
roots = rootWrapper(a,b,c,d)
|
||||
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(bezierpointatt(((bx0,by0),(bx1,by1),(bx2,by2),(bx3,by3)),i))
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
def tpoint((x1,y1),(x2,y2),t):
|
||||
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))
|
||||
|
||||
'''
|
||||
Approximating the arc length of a bezier curve
|
||||
according to <http://www.cit.gu.edu.au/~anthony/info/graphics/bezier.curves>
|
||||
|
||||
if:
|
||||
L1 = |P0 P1| +|P1 P2| +|P2 P3|
|
||||
L0 = |P0 P3|
|
||||
then:
|
||||
L = 1/2*L0 + 1/2*L1
|
||||
ERR = L1-L0
|
||||
ERR approaches 0 as the number of subdivisions (m) increases
|
||||
2^-4m
|
||||
|
||||
Reference:
|
||||
Jens Gravesen <gravesen@mat.dth.dk>
|
||||
"Adaptive subdivision and the length of Bezier curves"
|
||||
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))
|
||||
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)
|
||||
def bezierlengthGravesen(b, error = 0.001):
|
||||
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)
|
||||
|
||||
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
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
|
||||
#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)
|
||||
|
||||
|
||||
# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99
|
||||
@@ -1,38 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
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)
|
||||
|
||||
s1 = Segment(p0,p3)
|
||||
return max(s1.distanceToPoint(p1),s1.distanceToPoint(p2))
|
||||
|
||||
|
||||
def cspsubdiv(csp,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)
|
||||
@@ -1,169 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
cubicsuperpath.py
|
||||
|
||||
Copyright (C) 2005 Aaron Spike, aaron@ekips.org
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
"""
|
||||
import simplepath
|
||||
from math import *
|
||||
|
||||
def matprod(mlist):
|
||||
prod=mlist[0]
|
||||
for m in mlist[1:]:
|
||||
a00=prod[0][0]*m[0][0]+prod[0][1]*m[1][0]
|
||||
a01=prod[0][0]*m[0][1]+prod[0][1]*m[1][1]
|
||||
a10=prod[1][0]*m[0][0]+prod[1][1]*m[1][0]
|
||||
a11=prod[1][0]*m[0][1]+prod[1][1]*m[1][1]
|
||||
prod=[[a00,a01],[a10,a11]]
|
||||
return prod
|
||||
def rotmat(teta):
|
||||
return [[cos(teta),-sin(teta)],[sin(teta),cos(teta)]]
|
||||
def applymat(mat, pt):
|
||||
x=mat[0][0]*pt[0]+mat[0][1]*pt[1]
|
||||
y=mat[1][0]*pt[0]+mat[1][1]*pt[1]
|
||||
pt[0]=x
|
||||
pt[1]=y
|
||||
def norm(pt):
|
||||
return sqrt(pt[0]*pt[0]+pt[1]*pt[1])
|
||||
|
||||
def ArcToPath(p1,params):
|
||||
A=p1[:]
|
||||
rx,ry,teta,longflag,sweepflag,x2,y2=params[:]
|
||||
teta = teta*pi/180.0
|
||||
B=[x2,y2]
|
||||
if rx==0 or ry==0:
|
||||
return([[A,A,A],[B,B,B]])
|
||||
mat=matprod((rotmat(teta),[[1/rx,0],[0,1/ry]],rotmat(-teta)))
|
||||
applymat(mat, A)
|
||||
applymat(mat, B)
|
||||
k=[-(B[1]-A[1]),B[0]-A[0]]
|
||||
d=k[0]*k[0]+k[1]*k[1]
|
||||
k[0]/=sqrt(d)
|
||||
k[1]/=sqrt(d)
|
||||
d=sqrt(max(0,1-d/4))
|
||||
if longflag==sweepflag:
|
||||
d*=-1
|
||||
O=[(B[0]+A[0])/2+d*k[0],(B[1]+A[1])/2+d*k[1]]
|
||||
OA=[A[0]-O[0],A[1]-O[1]]
|
||||
OB=[B[0]-O[0],B[1]-O[1]]
|
||||
start=acos(OA[0]/norm(OA))
|
||||
if OA[1]<0:
|
||||
start*=-1
|
||||
end=acos(OB[0]/norm(OB))
|
||||
if OB[1]<0:
|
||||
end*=-1
|
||||
|
||||
if sweepflag and start>end:
|
||||
end +=2*pi
|
||||
if (not sweepflag) and start<end:
|
||||
end -=2*pi
|
||||
|
||||
NbSectors=int(abs(start-end)*2/pi)+1
|
||||
dTeta=(end-start)/NbSectors
|
||||
#v=dTeta*2/pi*0.552
|
||||
#v=dTeta*2/pi*4*(sqrt(2)-1)/3
|
||||
v = 4*tan(dTeta/4)/3
|
||||
#if not sweepflag:
|
||||
# v*=-1
|
||||
p=[]
|
||||
for i in range(0,NbSectors+1,1):
|
||||
angle=start+i*dTeta
|
||||
v1=[O[0]+cos(angle)-(-v)*sin(angle),O[1]+sin(angle)+(-v)*cos(angle)]
|
||||
pt=[O[0]+cos(angle) ,O[1]+sin(angle) ]
|
||||
v2=[O[0]+cos(angle)- v *sin(angle),O[1]+sin(angle)+ v *cos(angle)]
|
||||
p.append([v1,pt,v2])
|
||||
p[ 0][0]=p[ 0][1][:]
|
||||
p[-1][2]=p[-1][1][:]
|
||||
|
||||
mat=matprod((rotmat(teta),[[rx,0],[0,ry]],rotmat(-teta)))
|
||||
for pts in p:
|
||||
applymat(mat, pts[0])
|
||||
applymat(mat, pts[1])
|
||||
applymat(mat, pts[2])
|
||||
return(p)
|
||||
|
||||
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':
|
||||
q0=last[:]
|
||||
q1=params[0:2]
|
||||
q2=params[2:4]
|
||||
x0= q0[0]
|
||||
x1=1./3*q0[0]+2./3*q1[0]
|
||||
x2= 2./3*q1[0]+1./3*q2[0]
|
||||
x3= q2[0]
|
||||
y0= q0[1]
|
||||
y1=1./3*q0[1]+2./3*q1[1]
|
||||
y2= 2./3*q1[1]+1./3*q2[1]
|
||||
y3= q2[1]
|
||||
csp[subpath].append([lastctrl[:],[x0,y0],[x1,y1]])
|
||||
last = [x3,y3]
|
||||
lastctrl = [x2,y2]
|
||||
elif cmd == 'A':
|
||||
arcp=ArcToPath(last[:],params[:])
|
||||
arcp[ 0][0]=lastctrl[:]
|
||||
last=arcp[-1][1]
|
||||
lastctrl = arcp[-1][0]
|
||||
csp[subpath]+=arcp[:-1]
|
||||
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
|
||||
|
||||
def parsePath(d):
|
||||
return CubicSuperPath(simplepath.parsePath(d))
|
||||
|
||||
def formatPath(p):
|
||||
return simplepath.formatPath(unCubicSuperPath(p))
|
||||
|
||||
|
||||
# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99
|
||||
-189
@@ -1,189 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import logging
|
||||
import traceback
|
||||
import xml.etree.ElementTree as ET
|
||||
import simplepath
|
||||
import simpletransform
|
||||
import cubicsuperpath
|
||||
import cspsubdiv
|
||||
from bezmisc import beziersplitatt
|
||||
|
||||
|
||||
class svgshape(object):
|
||||
|
||||
def __init__(self, xml_node):
|
||||
self.xml_node = xml_node
|
||||
|
||||
def d_path(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def transformation_matrix(self):
|
||||
t = self.xml_node.get('transform')
|
||||
return simpletransform.parseTransform(t) if t is not None else None
|
||||
|
||||
def svg_path(self):
|
||||
return "<path d=\"" + self.d_path() + "\"/>"
|
||||
|
||||
def __str__(self):
|
||||
return self.xml_node
|
||||
|
||||
class path(svgshape):
|
||||
def __init__(self, xml_node):
|
||||
super(path, self).__init__(xml_node)
|
||||
|
||||
if not self.xml_node == None:
|
||||
path_el = self.xml_node
|
||||
self.d = path_el.get('d')
|
||||
else:
|
||||
self.d = None
|
||||
logging.error("path: Unable to get the attributes for %s", self.xml_node)
|
||||
|
||||
def d_path(self):
|
||||
return self.d
|
||||
|
||||
class rect(svgshape):
|
||||
|
||||
def __init__(self, xml_node):
|
||||
super(rect, self).__init__(xml_node)
|
||||
|
||||
if not self.xml_node == None:
|
||||
rect_el = self.xml_node
|
||||
self.x = float(rect_el.get('x')) if rect_el.get('x') else 0
|
||||
self.y = float(rect_el.get('y')) if rect_el.get('y') else 0
|
||||
self.rx = float(rect_el.get('rx')) if rect_el.get('rx') else 0
|
||||
self.ry = float(rect_el.get('ry')) if rect_el.get('ry') else 0
|
||||
self.width = float(rect_el.get('width')) if rect_el.get('width') else 0
|
||||
self.height = float(rect_el.get('height')) if rect_el.get('height') else 0
|
||||
else:
|
||||
self.x = self.y = self.rx = self.ry = self.width = self.height = 0
|
||||
logging.error("rect: Unable to get the attributes for %s", self.xml_node)
|
||||
|
||||
def d_path(self):
|
||||
a = list()
|
||||
a.append( ['M ', [self.x, self.y]] )
|
||||
a.append( [' l ', [self.width, 0]] )
|
||||
a.append( [' l ', [0, self.height]] )
|
||||
a.append( [' l ', [-self.width, 0]] )
|
||||
a.append( [' Z', []] )
|
||||
return simplepath.formatPath(a)
|
||||
|
||||
class ellipse(svgshape):
|
||||
|
||||
def __init__(self, xml_node):
|
||||
super(ellipse, self).__init__(xml_node)
|
||||
|
||||
if not self.xml_node == None:
|
||||
ellipse_el = self.xml_node
|
||||
self.cx = float(ellipse_el.get('cx')) if ellipse_el.get('cx') else 0
|
||||
self.cy = float(ellipse_el.get('cy')) if ellipse_el.get('cy') else 0
|
||||
self.rx = float(ellipse_el.get('rx')) if ellipse_el.get('rx') else 0
|
||||
self.ry = float(ellipse_el.get('ry')) if ellipse_el.get('ry') else 0
|
||||
else:
|
||||
self.cx = self.cy = self.rx = self.ry = 0
|
||||
logging.error("ellipse: Unable to get the attributes for %s", self.xml_node)
|
||||
|
||||
def d_path(self):
|
||||
x1 = self.cx - self.rx
|
||||
x2 = self.cx + self.rx
|
||||
p = 'M %f,%f ' % ( x1, self.cy ) + \
|
||||
'A %f,%f ' % ( self.rx, self.ry ) + \
|
||||
'0 1 0 %f,%f ' % ( x2, self.cy ) + \
|
||||
'A %f,%f ' % ( self.rx, self.ry ) + \
|
||||
'0 1 0 %f,%f' % ( x1, self.cy )
|
||||
return p
|
||||
|
||||
class circle(ellipse):
|
||||
def __init__(self, xml_node):
|
||||
super(ellipse, self).__init__(xml_node)
|
||||
|
||||
if not self.xml_node == None:
|
||||
circle_el = self.xml_node
|
||||
self.cx = float(circle_el.get('cx')) if circle_el.get('cx') else 0
|
||||
self.cy = float(circle_el.get('cy')) if circle_el.get('cy') else 0
|
||||
self.rx = float(circle_el.get('r')) if circle_el.get('r') else 0
|
||||
self.ry = self.rx
|
||||
else:
|
||||
self.cx = self.cy = self.r = 0
|
||||
logging.error("Circle: Unable to get the attributes for %s", self.xml_node)
|
||||
|
||||
class line(svgshape):
|
||||
|
||||
def __init__(self, xml_node):
|
||||
super(line, self).__init__(xml_node)
|
||||
|
||||
if not self.xml_node == None:
|
||||
line_el = self.xml_node
|
||||
self.x1 = float(line_el.get('x1')) if line_el.get('x1') else 0
|
||||
self.y1 = float(line_el.get('y1')) if line_el.get('y1') else 0
|
||||
self.x2 = float(line_el.get('x2')) if line_el.get('x2') else 0
|
||||
self.y2 = float(line_el.get('y2')) if line_el.get('y2') else 0
|
||||
else:
|
||||
self.x1 = self.y1 = self.x2 = self.y2 = 0
|
||||
logging.error("line: Unable to get the attributes for %s", self.xml_node)
|
||||
|
||||
def d_path(self):
|
||||
a = []
|
||||
a.append( ['M ', [self.x1, self.y1]] )
|
||||
a.append( ['L ', [self.x2, self.y2]] )
|
||||
return simplepath.formatPath(a)
|
||||
|
||||
class polycommon(svgshape):
|
||||
|
||||
def __init__(self, xml_node, polytype):
|
||||
super(polycommon, self).__init__(xml_node)
|
||||
self.points = list()
|
||||
|
||||
if not self.xml_node == None:
|
||||
polycommon_el = self.xml_node
|
||||
points = polycommon_el.get('points') if polycommon_el.get('points') else list()
|
||||
for pa in points.split():
|
||||
self.points.append(pa)
|
||||
else:
|
||||
logging.error("polycommon: Unable to get the attributes for %s", self.xml_node)
|
||||
|
||||
|
||||
class polygon(polycommon):
|
||||
|
||||
def __init__(self, xml_node):
|
||||
super(polygon, self).__init__(xml_node, 'polygon')
|
||||
|
||||
def d_path(self):
|
||||
d = "M " + self.points[0]
|
||||
for i in range( 1, len(self.points) ):
|
||||
d += " L " + self.points[i]
|
||||
d += " Z"
|
||||
return d
|
||||
|
||||
class polyline(polycommon):
|
||||
|
||||
def __init__(self, xml_node):
|
||||
super(polyline, self).__init__(xml_node, 'polyline')
|
||||
|
||||
def d_path(self):
|
||||
d = "M " + self.points[0]
|
||||
for i in range( 1, len(self.points) ):
|
||||
d += " L " + self.points[i]
|
||||
return d
|
||||
|
||||
def point_generator(path, mat, flatness):
|
||||
|
||||
if len(simplepath.parsePath(path)) == 0:
|
||||
return
|
||||
|
||||
simple_path = simplepath.parsePath(path)
|
||||
startX,startY = float(simple_path[0][1][0]), float(simple_path[0][1][1])
|
||||
yield startX, startY
|
||||
|
||||
p = cubicsuperpath.parsePath(path)
|
||||
|
||||
if mat:
|
||||
simpletransform.applyTransformToPath(mat, p)
|
||||
|
||||
for sp in p:
|
||||
cspsubdiv.subdiv( sp, flatness)
|
||||
for csp in sp:
|
||||
ctrl_pt1 = csp[0]
|
||||
ctrl_pt2 = csp[1]
|
||||
end_pt = csp[2]
|
||||
yield end_pt[0], end_pt[1],
|
||||
@@ -1,202 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
simplepath.py
|
||||
functions for digesting paths into a simple list structure
|
||||
|
||||
Copyright (C) 2005 Aaron Spike, aaron@ekips.org
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
"""
|
||||
import re, math
|
||||
|
||||
def lexPath(d):
|
||||
"""
|
||||
returns and iterator that breaks path data
|
||||
identifies command and parameter tokens
|
||||
"""
|
||||
offset = 0
|
||||
length = len(d)
|
||||
delim = re.compile(r'[ \t\r\n,]+')
|
||||
command = re.compile(r'[MLHVCSQTAZmlhvcsqtaz]')
|
||||
parameter = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)')
|
||||
while 1:
|
||||
m = delim.match(d, offset)
|
||||
if m:
|
||||
offset = m.end()
|
||||
if offset >= length:
|
||||
break
|
||||
m = command.match(d, offset)
|
||||
if m:
|
||||
yield [d[offset:m.end()], True]
|
||||
offset = m.end()
|
||||
continue
|
||||
m = parameter.match(d, offset)
|
||||
if m:
|
||||
yield [d[offset:m.end()], False]
|
||||
offset = m.end()
|
||||
continue
|
||||
#TODO: create new exception
|
||||
raise Exception, 'Invalid path data!'
|
||||
'''
|
||||
pathdefs = {commandfamily:
|
||||
[
|
||||
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, [], []]
|
||||
}
|
||||
def parsePath(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 lastCommand.isupper():
|
||||
command = pathdefs[lastCommand][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])
|
||||
pen = subPathStart
|
||||
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
|
||||
|
||||
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])
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
@@ -1,241 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
'''
|
||||
Copyright (C) 2006 Jean-Francois Barraud, barraud@math.univ-lille1.fr
|
||||
Copyright (C) 2010 Alvin Penner, penner@vaxxine.com
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
barraud@math.univ-lille1.fr
|
||||
|
||||
This code defines several functions to make handling of transform
|
||||
attribute easier.
|
||||
'''
|
||||
import cubicsuperpath, bezmisc
|
||||
import copy, math, re
|
||||
|
||||
def parseTransform(transf,mat=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]):
|
||||
if transf=="" or transf==None:
|
||||
return(mat)
|
||||
stransf = transf.strip()
|
||||
result=re.match("(translate|scale|rotate|skewX|skewY|matrix)\s*\(([^)]*)\)\s*,?",stransf)
|
||||
#-- translate --
|
||||
if result.group(1)=="translate":
|
||||
args=result.group(2).replace(',',' ').split()
|
||||
dx=float(args[0])
|
||||
if len(args)==1:
|
||||
dy=0.0
|
||||
else:
|
||||
dy=float(args[1])
|
||||
matrix=[[1,0,dx],[0,1,dy]]
|
||||
#-- scale --
|
||||
if result.group(1)=="scale":
|
||||
args=result.group(2).replace(',',' ').split()
|
||||
sx=float(args[0])
|
||||
if len(args)==1:
|
||||
sy=sx
|
||||
else:
|
||||
sy=float(args[1])
|
||||
matrix=[[sx,0,0],[0,sy,0]]
|
||||
#-- rotate --
|
||||
if result.group(1)=="rotate":
|
||||
args=result.group(2).replace(',',' ').split()
|
||||
a=float(args[0])*math.pi/180
|
||||
if len(args)==1:
|
||||
cx,cy=(0.0,0.0)
|
||||
else:
|
||||
cx,cy=map(float,args[1:])
|
||||
matrix=[[math.cos(a),-math.sin(a),cx],[math.sin(a),math.cos(a),cy]]
|
||||
matrix=composeTransform(matrix,[[1,0,-cx],[0,1,-cy]])
|
||||
#-- skewX --
|
||||
if result.group(1)=="skewX":
|
||||
a=float(result.group(2))*math.pi/180
|
||||
matrix=[[1,math.tan(a),0],[0,1,0]]
|
||||
#-- skewY --
|
||||
if result.group(1)=="skewY":
|
||||
a=float(result.group(2))*math.pi/180
|
||||
matrix=[[1,0,0],[math.tan(a),1,0]]
|
||||
#-- matrix --
|
||||
if result.group(1)=="matrix":
|
||||
a11,a21,a12,a22,v1,v2=result.group(2).replace(',',' ').split()
|
||||
matrix=[[float(a11),float(a12),float(v1)], [float(a21),float(a22),float(v2)]]
|
||||
|
||||
matrix=composeTransform(mat,matrix)
|
||||
if result.end() < len(stransf):
|
||||
return(parseTransform(stransf[result.end():], matrix))
|
||||
else:
|
||||
return matrix
|
||||
|
||||
def formatTransform(mat):
|
||||
return ("matrix(%f,%f,%f,%f,%f,%f)" % (mat[0][0], mat[1][0], mat[0][1], mat[1][1], mat[0][2], mat[1][2]))
|
||||
|
||||
def composeTransform(M1,M2):
|
||||
a11 = M1[0][0]*M2[0][0] + M1[0][1]*M2[1][0]
|
||||
a12 = M1[0][0]*M2[0][1] + M1[0][1]*M2[1][1]
|
||||
a21 = M1[1][0]*M2[0][0] + M1[1][1]*M2[1][0]
|
||||
a22 = M1[1][0]*M2[0][1] + M1[1][1]*M2[1][1]
|
||||
|
||||
v1 = M1[0][0]*M2[0][2] + M1[0][1]*M2[1][2] + M1[0][2]
|
||||
v2 = M1[1][0]*M2[0][2] + M1[1][1]*M2[1][2] + M1[1][2]
|
||||
return [[a11,a12,v1],[a21,a22,v2]]
|
||||
|
||||
def composeParents(node, mat):
|
||||
trans = node.get('transform')
|
||||
if trans:
|
||||
mat = composeTransform(parseTransform(trans), mat)
|
||||
if node.getparent().tag == inkex.addNS('g','svg'):
|
||||
mat = composeParents(node.getparent(), mat)
|
||||
return mat
|
||||
|
||||
def applyTransformToNode(mat,node):
|
||||
m=parseTransform(node.get("transform"))
|
||||
newtransf=formatTransform(composeTransform(mat,m))
|
||||
node.set("transform", newtransf)
|
||||
|
||||
def applyTransformToPoint(mat,pt):
|
||||
x = mat[0][0]*pt[0] + mat[0][1]*pt[1] + mat[0][2]
|
||||
y = mat[1][0]*pt[0] + mat[1][1]*pt[1] + mat[1][2]
|
||||
pt[0]=x
|
||||
pt[1]=y
|
||||
|
||||
def applyTransformToPath(mat,path):
|
||||
for comp in path:
|
||||
for ctl in comp:
|
||||
for pt in ctl:
|
||||
applyTransformToPoint(mat,pt)
|
||||
|
||||
def fuseTransform(node):
|
||||
if node.get('d')==None:
|
||||
#FIXME: how do you raise errors?
|
||||
raise AssertionError, 'can not fuse "transform" of elements that have no "d" attribute'
|
||||
t = node.get("transform")
|
||||
if t == None:
|
||||
return
|
||||
m = parseTransform(t)
|
||||
d = node.get('d')
|
||||
p = cubicsuperpath.parsePath(d)
|
||||
applyTransformToPath(m,p)
|
||||
node.set('d', cubicsuperpath.formatPath(p))
|
||||
del node.attrib["transform"]
|
||||
|
||||
####################################################################
|
||||
##-- Some functions to compute a rough bbox of a given list of objects.
|
||||
##-- this should be shipped out in an separate file...
|
||||
|
||||
def boxunion(b1,b2):
|
||||
if b1 is None:
|
||||
return b2
|
||||
elif b2 is None:
|
||||
return b1
|
||||
else:
|
||||
return((min(b1[0],b2[0]), max(b1[1],b2[1]), min(b1[2],b2[2]), max(b1[3],b2[3])))
|
||||
|
||||
def roughBBox(path):
|
||||
xmin,xMax,ymin,yMax = path[0][0][0][0],path[0][0][0][0],path[0][0][0][1],path[0][0][0][1]
|
||||
for pathcomp in path:
|
||||
for ctl in pathcomp:
|
||||
for pt in ctl:
|
||||
xmin = min(xmin,pt[0])
|
||||
xMax = max(xMax,pt[0])
|
||||
ymin = min(ymin,pt[1])
|
||||
yMax = max(yMax,pt[1])
|
||||
return xmin,xMax,ymin,yMax
|
||||
|
||||
def refinedBBox(path):
|
||||
xmin,xMax,ymin,yMax = path[0][0][1][0],path[0][0][1][0],path[0][0][1][1],path[0][0][1][1]
|
||||
for pathcomp in path:
|
||||
for i in range(1, len(pathcomp)):
|
||||
cmin, cmax = cubicExtrema(pathcomp[i-1][1][0], pathcomp[i-1][2][0], pathcomp[i][0][0], pathcomp[i][1][0])
|
||||
xmin = min(xmin, cmin)
|
||||
xMax = max(xMax, cmax)
|
||||
cmin, cmax = cubicExtrema(pathcomp[i-1][1][1], pathcomp[i-1][2][1], pathcomp[i][0][1], pathcomp[i][1][1])
|
||||
ymin = min(ymin, cmin)
|
||||
yMax = max(yMax, cmax)
|
||||
return xmin,xMax,ymin,yMax
|
||||
|
||||
def cubicExtrema(y0, y1, y2, y3):
|
||||
cmin = min(y0, y3)
|
||||
cmax = max(y0, y3)
|
||||
d1 = y1 - y0
|
||||
d2 = y2 - y1
|
||||
d3 = y3 - y2
|
||||
if (d1 - 2*d2 + d3):
|
||||
if (d2*d2 > d1*d3):
|
||||
t = (d1 - d2 + math.sqrt(d2*d2 - d1*d3))/(d1 - 2*d2 + d3)
|
||||
if (t > 0) and (t < 1):
|
||||
y = y0*(1-t)*(1-t)*(1-t) + 3*y1*t*(1-t)*(1-t) + 3*y2*t*t*(1-t) + y3*t*t*t
|
||||
cmin = min(cmin, y)
|
||||
cmax = max(cmax, y)
|
||||
t = (d1 - d2 - math.sqrt(d2*d2 - d1*d3))/(d1 - 2*d2 + d3)
|
||||
if (t > 0) and (t < 1):
|
||||
y = y0*(1-t)*(1-t)*(1-t) + 3*y1*t*(1-t)*(1-t) + 3*y2*t*t*(1-t) + y3*t*t*t
|
||||
cmin = min(cmin, y)
|
||||
cmax = max(cmax, y)
|
||||
elif (d3 - d1):
|
||||
t = -d1/(d3 - d1)
|
||||
if (t > 0) and (t < 1):
|
||||
y = y0*(1-t)*(1-t)*(1-t) + 3*y1*t*(1-t)*(1-t) + 3*y2*t*t*(1-t) + y3*t*t*t
|
||||
cmin = min(cmin, y)
|
||||
cmax = max(cmax, y)
|
||||
return cmin, cmax
|
||||
|
||||
def computeBBox(aList,mat=[[1,0,0],[0,1,0]]):
|
||||
bbox=None
|
||||
for node in aList:
|
||||
m = parseTransform(node.get('transform'))
|
||||
m = composeTransform(mat,m)
|
||||
#TODO: text not supported!
|
||||
d = None
|
||||
if node.get("d"):
|
||||
d = node.get('d')
|
||||
elif node.get('points'):
|
||||
d = 'M' + node.get('points')
|
||||
elif node.tag in [ inkex.addNS('rect','svg'), 'rect', inkex.addNS('image','svg'), 'image' ]:
|
||||
d = 'M' + node.get('x', '0') + ',' + node.get('y', '0') + \
|
||||
'h' + node.get('width') + 'v' + node.get('height') + \
|
||||
'h-' + node.get('width')
|
||||
elif node.tag in [ inkex.addNS('line','svg'), 'line' ]:
|
||||
d = 'M' + node.get('x1') + ',' + node.get('y1') + \
|
||||
' ' + node.get('x2') + ',' + node.get('y2')
|
||||
elif node.tag in [ inkex.addNS('circle','svg'), 'circle', \
|
||||
inkex.addNS('ellipse','svg'), 'ellipse' ]:
|
||||
rx = node.get('r')
|
||||
if rx is not None:
|
||||
ry = rx
|
||||
else:
|
||||
rx = node.get('rx')
|
||||
ry = node.get('ry')
|
||||
cx = float(node.get('cx', '0'))
|
||||
cy = float(node.get('cy', '0'))
|
||||
x1 = cx - float(rx)
|
||||
x2 = cx + float(rx)
|
||||
d = 'M %f %f ' % (x1, cy) + \
|
||||
'A' + rx + ',' + ry + ' 0 1 0 %f,%f' % (x2, cy) + \
|
||||
'A' + rx + ',' + ry + ' 0 1 0 %f,%f' % (x1, cy)
|
||||
|
||||
if d is not None:
|
||||
p = cubicsuperpath.parsePath(d)
|
||||
applyTransformToPath(m,p)
|
||||
bbox=boxunion(refinedBBox(p),bbox)
|
||||
|
||||
elif node.tag == inkex.addNS('use','svg') or node.tag=='use':
|
||||
refid=node.get(inkex.addNS('href','xlink'))
|
||||
path = '//*[@id="%s"]' % refid[1:]
|
||||
refnode = node.xpath(path)
|
||||
bbox=boxunion(computeBBox(refnode,m),bbox)
|
||||
|
||||
bbox=boxunion(computeBBox(node,m),bbox)
|
||||
return bbox
|
||||
|
||||
|
||||
# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99
|
||||
-6122
File diff suppressed because it is too large.
Load diff
-160413
File diff suppressed because it is too large.
Load diff
|
Before Width: | Height: | Size: 12 MiB |
-6185
File diff suppressed because it is too large.
Load diff
-59356
File diff suppressed because it is too large.
Load diff
|
Before Width: | Height: | Size: 5.0 MiB |
@@ -1,61 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import sys
|
||||
import xml.etree.ElementTree as ET
|
||||
import shapes as shapes_pkg
|
||||
from shapes import point_generator
|
||||
from config import *
|
||||
|
||||
def generate_gcode():
|
||||
svg_shapes = set(['rect', 'circle', 'ellipse', 'line', 'polyline', 'polygon', 'path'])
|
||||
|
||||
tree = ET.parse(sys.stdin)
|
||||
root = tree.getroot()
|
||||
|
||||
width = root.get('width')
|
||||
height = root.get('height')
|
||||
if width == None or height == None:
|
||||
viewbox = root.get('viewBox')
|
||||
if viewbox:
|
||||
_, _, width, height = viewbox.split()
|
||||
|
||||
if width == None or height == None:
|
||||
print "Unable to get width and height for the svg"
|
||||
sys.exit(1)
|
||||
|
||||
width = float(width)
|
||||
height = float(height)
|
||||
|
||||
scale_x = bed_max_x / max(width, height)
|
||||
scale_y = bed_max_y / max(width, height)
|
||||
|
||||
print preamble
|
||||
|
||||
for elem in root.iter():
|
||||
|
||||
try:
|
||||
_, tag_suffix = elem.tag.split('}')
|
||||
except ValueError:
|
||||
continue
|
||||
|
||||
if tag_suffix in svg_shapes:
|
||||
shape_class = getattr(shapes_pkg, tag_suffix)
|
||||
shape_obj = shape_class(elem)
|
||||
d = shape_obj.d_path()
|
||||
m = shape_obj.transformation_matrix()
|
||||
|
||||
if d:
|
||||
print shape_preamble
|
||||
p = point_generator(d, m, smoothness)
|
||||
for x,y in p:
|
||||
if x > 0 and x < bed_max_x and y > 0 and y < bed_max_y:
|
||||
print "G1 X%0.1f Y%0.1f" % (scale_x*x, scale_y*y)
|
||||
print shape_postamble
|
||||
|
||||
print postamble
|
||||
|
||||
if __name__ == "__main__":
|
||||
generate_gcode()
|
||||
|
||||
|
||||
|
||||
-652789
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user