Initial commit
This commit is contained in:
commit
a58b7bc8c9
9 files changed
+1063
No files matched your search
Executable
Whitespace-only changes.
Executable
+274
@@ -0,0 +1,274 @@
|
||||
#!/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
|
||||
Executable
+38
@@ -0,0 +1,38 @@
|
||||
#!/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)
|
||||
Executable
+169
@@ -0,0 +1,169 @@
|
||||
#!/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
|
||||
@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
ffgeom.py
|
||||
Copyright (C) 2005 Aaron Cyril Spike, aaron@ekips.org
|
||||
|
||||
This file is part of FretFind 2-D.
|
||||
|
||||
FretFind 2-D 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.
|
||||
|
||||
FretFind 2-D 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 FretFind 2-D; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
"""
|
||||
import math
|
||||
try:
|
||||
NaN = float('NaN')
|
||||
except ValueError:
|
||||
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)
|
||||
|
||||
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 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))
|
||||
|
||||
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)
|
||||
|
||||
def dot(s1, s2):
|
||||
return s1.delta_x() * s2.delta_x() + s1.delta_y() * s2.delta_y()
|
||||
|
||||
|
||||
# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99
|
||||
@@ -0,0 +1,208 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import logging
|
||||
import xml.etree.ElementTree as ET
|
||||
import simplepath
|
||||
import cubicsuperpath
|
||||
import cspsubdiv
|
||||
from bezmisc import beziersplitatt
|
||||
|
||||
|
||||
class svgshape(object):
|
||||
|
||||
def __init__(self, xml):
|
||||
self.xml = xml.lower()
|
||||
self.xml_tree = None
|
||||
try:
|
||||
self.xml_tree = ET.fromstring(xml)
|
||||
except:
|
||||
logging.error("Unable to parse xml %s", xml)
|
||||
|
||||
def d_path(self):
|
||||
raise NotImplementedError
|
||||
|
||||
def svg_path(self):
|
||||
return "<path d=\"" + self.d_path() + "\"/>"
|
||||
|
||||
def __str__(self):
|
||||
return self.xml
|
||||
|
||||
class path(svgshape):
|
||||
def __init__(self, xml):
|
||||
super(path, self).__init__(xml)
|
||||
|
||||
if (not (self.xml_tree == None) and self.xml_tree.tag == 'path'):
|
||||
path_el = self.xml_tree
|
||||
self.d = path_el.get('d')
|
||||
else:
|
||||
self.d = None
|
||||
logging.error("path: Unable to get the attributes for %s", self.xml)
|
||||
|
||||
def d_path(self):
|
||||
return self.d
|
||||
|
||||
class rect(svgshape):
|
||||
|
||||
def __init__(self, xml):
|
||||
super(rect, self).__init__(xml)
|
||||
|
||||
if (not (self.xml_tree == None) and self.xml_tree.tag == 'rect'):
|
||||
rect_el = self.xml_tree
|
||||
self.x = int(rect_el.get('x')) if rect_el.get('x') else 0
|
||||
self.y = int(rect_el.get('y')) if rect_el.get('y') else 0
|
||||
self.rx = int(rect_el.get('rx')) if rect_el.get('rx') else 0
|
||||
self.ry = int(rect_el.get('ry')) if rect_el.get('ry') else 0
|
||||
self.width = int(rect_el.get('width')) if rect_el.get('width') else 0
|
||||
self.height = int(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)
|
||||
|
||||
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):
|
||||
super(ellipse, self).__init__(xml)
|
||||
|
||||
if (not (self.xml_tree == None) and self.xml_tree.tag == 'ellipse'):
|
||||
ellipse_el = self.xml_tree
|
||||
self.cx = int(ellipse_el.get('cx')) if ellipse_el.get('cx') else 0
|
||||
self.cy = int(ellipse_el.get('cy')) if ellipse_el.get('cy') else 0
|
||||
self.rx = int(ellipse_el.get('rx')) if ellipse_el.get('rx') else 0
|
||||
self.ry = int(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)
|
||||
|
||||
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):
|
||||
super(ellipse, self).__init__(xml)
|
||||
|
||||
if (not (self.xml_tree == None) and self.xml_tree.tag == 'circle'):
|
||||
circle_el = self.xml_tree
|
||||
self.cx = int(circle_el.get('cx')) if circle_el.get('cx') else 0
|
||||
self.cy = int(circle_el.get('cy')) if circle_el.get('cy') else 0
|
||||
self.rx = int(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)
|
||||
|
||||
class line(svgshape):
|
||||
|
||||
def __init__(self, xml):
|
||||
super(line, self).__init__(xml)
|
||||
|
||||
if (not (self.xml_tree == None) and self.xml_tree.tag == 'line'):
|
||||
line_el = self.xml_tree
|
||||
self.x1 = int(line_el.get('x1')) if line_el.get('x1') else 0
|
||||
self.y1 = int(line_el.get('y1')) if line_el.get('y1') else 0
|
||||
self.x2 = int(line_el.get('x2')) if line_el.get('x2') else 0
|
||||
self.y2 = int(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)
|
||||
|
||||
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, polytype):
|
||||
super(polycommon, self).__init__(xml)
|
||||
self.points = list()
|
||||
|
||||
if (not (self.xml_tree == None) and self.xml_tree.tag == polytype):
|
||||
polycommon_el = self.xml_tree
|
||||
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)
|
||||
|
||||
|
||||
class polygon(polycommon):
|
||||
|
||||
def __init__(self, xml):
|
||||
super(polygon, self).__init__(xml, '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):
|
||||
super(polyline, self).__init__(xml, '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):
|
||||
|
||||
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)
|
||||
for sp in p:
|
||||
cspsubdiv.subdiv( sp, .2 )
|
||||
for csp in sp:
|
||||
ctrl_pt1 = csp[0]
|
||||
ctrl_pt2 = csp[1]
|
||||
end_pt = csp[2]
|
||||
yield end_pt[0], end_pt[1],
|
||||
|
||||
if __name__ == "__main__":
|
||||
svg_rect = """<rect x="1" y="1" width="200" height="300"/>"""
|
||||
r = rect(svg_rect)
|
||||
assert r.svg_path() == """<path d="M 1 1 l 200 0 l 0 300 l -200 0 Z"/>"""
|
||||
|
||||
svg_line = """<line x1="0" y1="0" x2="200" y2="200"/>"""
|
||||
l = line(svg_line)
|
||||
|
||||
svg_circle = """<circle cx="100" cy="50" r="40"/>"""
|
||||
c = circle(svg_circle)
|
||||
assert c.svg_path() == """<path d="M 60.000000,50.000000 A 40.000000,40.000000 0 1 0 140.000000,50.000000 A 40.000000,40.000000 0 1 0 60.000000,50.000000"/>"""
|
||||
|
||||
svg_ellipse = """<ellipse cx="300" cy="80" rx="100" ry="50"/>"""
|
||||
c = ellipse(svg_ellipse)
|
||||
assert c.svg_path() == """<path d="M 200.000000,80.000000 A 100.000000,50.000000 0 1 0 400.000000,80.000000 A 100.000000,50.000000 0 1 0 200.000000,80.000000"/>"""
|
||||
|
||||
svg_polyline = """<polyline points="0,40 40,40 40,80 80,80 80,120 120,120 120,160"/>"""
|
||||
p = polyline(svg_polyline)
|
||||
assert p.svg_path() == """<path d="M 0,40 L 40,40 L 40,80 L 80,80 L 80,120 L 120,120 L 120,160"/>"""
|
||||
|
||||
svg_polygon = """<polygon points="200,10 250,190 160,210"/>"""
|
||||
p = polygon(svg_polygon)
|
||||
assert p.svg_path() == """<path d="M 200,10 L 250,190 L 160,210 Z"/>"""
|
||||
Executable
+202
@@ -0,0 +1,202 @@
|
||||
#!/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
|
||||
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
from xml.dom import minidom
|
||||
import sys
|
||||
|
||||
import shapes as shapes_pkg
|
||||
from shapes import point_generator
|
||||
|
||||
svg_shapes = ['rect', 'circle', 'ellipse', 'line', 'polyline', 'polygon', 'path']
|
||||
|
||||
def generate_gcode():
|
||||
dom = minidom.parse(sys.stdin)
|
||||
print "G28\n\n G1 Z5.0\n\n"
|
||||
for svg_shape in svg_shapes:
|
||||
shapes = dom.getElementsByTagName(svg_shape)
|
||||
for shape in shapes:
|
||||
shape_class = getattr(shapes_pkg, shape.nodeName)
|
||||
shape_obj = shape_class(shape.toxml())
|
||||
print "G4 P200"
|
||||
p = point_generator(shape_obj.d_path())
|
||||
for x,y in p:
|
||||
print "G1 X%0.1f Y%0.1f" % (x, y)
|
||||
print "G28"
|
||||
dom.unlink()
|
||||
|
||||
if __name__ == "__main__":
|
||||
generate_gcode()
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user