1 #!/usr/bin/env python
2 """
3 cubicsuperpath.py
5 Copyright (C) 2005 Aaron Spike, aaron@ekips.org
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 """
22 import simplepath
23 from math import *
25 def matprod(mlist):
26 prod=mlist[0]
27 for m in mlist[1:]:
28 a00=prod[0][0]*m[0][0]+prod[0][1]*m[1][0]
29 a01=prod[0][0]*m[0][1]+prod[0][1]*m[1][1]
30 a10=prod[1][0]*m[0][0]+prod[1][1]*m[1][0]
31 a11=prod[1][0]*m[0][1]+prod[1][1]*m[1][1]
32 prod=[[a00,a01],[a10,a11]]
33 return prod
34 def rotmat(teta):
35 return [[cos(teta),-sin(teta)],[sin(teta),cos(teta)]]
36 def applymat(mat, pt):
37 x=mat[0][0]*pt[0]+mat[0][1]*pt[1]
38 y=mat[1][0]*pt[0]+mat[1][1]*pt[1]
39 pt[0]=x
40 pt[1]=y
41 def norm(pt):
42 return sqrt(pt[0]*pt[0]+pt[1]*pt[1])
44 def ArcToPath(p1,params):
45 A=p1[:]
46 rx,ry,teta,longflag,sweepflag,x2,y2=params[:]
47 B=[x2,y2]
48 if rx==0 or ry==0:
49 return([[A,A,A],[B,B,B]])
50 mat=matprod((rotmat(teta),[[1/rx,0],[0,1/ry]],rotmat(-teta)))
51 applymat(mat, A)
52 applymat(mat, B)
53 k=[-(B[1]-A[1]),B[0]-A[0]]
54 d=k[0]*k[0]+k[1]*k[1]
55 k[0]/=sqrt(d)
56 k[1]/=sqrt(d)
57 d=sqrt(max(0,1-d/4))
58 if longflag==sweepflag:
59 d*=-1
60 O=[(B[0]+A[0])/2+d*k[0],(B[1]+A[1])/2+d*k[1]]
61 OA=[A[0]-O[0],A[1]-O[1]]
62 OB=[B[0]-O[0],B[1]-O[1]]
63 start=acos(OA[0]/norm(OA))
64 if OA[1]<0:
65 start*=-1
66 end=acos(OB[0]/norm(OB))
67 if OB[1]<0:
68 end*=-1
70 if sweepflag and start>end:
71 end +=2*pi
72 if (not sweepflag) and start<end:
73 end -=2*pi
75 NbSectors=int(abs(start-end)*2/pi)+1
76 dTeta=(end-start)/NbSectors
77 #v=dTeta*2/pi*0.552
78 v=dTeta*2/pi*4*(sqrt(2)-1)/3
79 #if not sweepflag:
80 # v*=-1
81 p=[]
82 for i in range(0,NbSectors+1,1):
83 angle=start+i*dTeta
84 v1=[O[0]+cos(angle)-(-v)*sin(angle),O[1]+sin(angle)+(-v)*cos(angle)]
85 pt=[O[0]+cos(angle) ,O[1]+sin(angle) ]
86 v2=[O[0]+cos(angle)- v *sin(angle),O[1]+sin(angle)+ v *cos(angle)]
87 p.append([v1,pt,v2])
88 p[ 0][0]=p[ 0][1][:]
89 p[-1][2]=p[-1][1][:]
91 mat=matprod((rotmat(teta),[[rx,0],[0,ry]],rotmat(-teta)))
92 for pts in p:
93 applymat(mat, pts[0])
94 applymat(mat, pts[1])
95 applymat(mat, pts[2])
96 return(p)
98 def CubicSuperPath(simplepath):
99 csp = []
100 subpath = -1
101 subpathstart = []
102 last = []
103 lastctrl = []
104 for s in simplepath:
105 cmd, params = s
106 if cmd == 'M':
107 if last:
108 csp[subpath].append([lastctrl[:],last[:],last[:]])
109 subpath += 1
110 csp.append([])
111 subpathstart = params[:]
112 last = params[:]
113 lastctrl = params[:]
114 elif cmd == 'L':
115 csp[subpath].append([lastctrl[:],last[:],last[:]])
116 last = params[:]
117 lastctrl = params[:]
118 elif cmd == 'C':
119 csp[subpath].append([lastctrl[:],last[:],params[:2]])
120 last = params[-2:]
121 lastctrl = params[2:4]
122 elif cmd == 'Q':
123 q0=last[:]
124 q1=params[0:1]
125 q2=params[2:3]
126 x0= q0[0]
127 x1=1/3*q0[0]+2/3*q1[0]
128 x2= 2/3*q1[0]+1/3*q2[0]
129 x3= q2[0]
130 y0= q0[1]
131 y1=1/3*q0[1]+2/3*q1[1]
132 y2= 2/3*q1[1]+1/3*q2[1]
133 y3= q2[1]
134 csp[subpath].append([lastctrl[:][x0,y0][x1,y1]])
135 last = [x3,y3]
136 lastctrl = [x2,y2]
137 elif cmd == 'A':
138 arcp=ArcToPath(last[:],params[:])
139 arcp[ 0][0]=lastctrl[:]
140 last=arcp[-1][1]
141 lastctrl = arcp[-1][0]
142 csp[subpath]+=arcp[:-1]
143 elif cmd == 'Z':
144 csp[subpath].append([lastctrl[:],last[:],last[:]])
145 last = subpathstart[:]
146 lastctrl = subpathstart[:]
147 #append final superpoint
148 csp[subpath].append([lastctrl[:],last[:],last[:]])
149 return csp
151 def unCubicSuperPath(csp):
152 a = []
153 for subpath in csp:
154 if subpath:
155 a.append(['M',subpath[0][1][:]])
156 for i in range(1,len(subpath)):
157 a.append(['C',subpath[i-1][2][:] + subpath[i][0][:] + subpath[i][1][:]])
158 return a
160 def parsePath(d):
161 return CubicSuperPath(simplepath.parsePath(d))
163 def formatPath(p):
164 return simplepath.formatPath(unCubicSuperPath(p))