Sat, 23 Sep 2017 10:27:49 +0200
Added more default options
Code cleanup
16 | 1 | #!/usr/bin/env python |
2 | """ | |
3 | cubicsuperpath.py | |
4 | ||
5 | Copyright (C) 2005 Aaron Spike, aaron@ekips.org | |
6 | ||
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. | |
11 | ||
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. | |
16 | ||
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 | |
20 | ||
21 | """ | |
22 | import simplepath | |
23 | from math import * | |
24 | ||
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]) | |
43 | ||
44 | def ArcToPath(p1,params): | |
45 | A=p1[:] | |
46 | rx,ry,teta,longflag,sweepflag,x2,y2=params[:] | |
47 | teta = teta*pi/180.0 | |
48 | B=[x2,y2] | |
49 | if rx==0 or ry==0: | |
50 | return([[A,A,A],[B,B,B]]) | |
51 | mat=matprod((rotmat(teta),[[1/rx,0],[0,1/ry]],rotmat(-teta))) | |
52 | applymat(mat, A) | |
53 | applymat(mat, B) | |
54 | k=[-(B[1]-A[1]),B[0]-A[0]] | |
55 | d=k[0]*k[0]+k[1]*k[1] | |
56 | k[0]/=sqrt(d) | |
57 | k[1]/=sqrt(d) | |
58 | d=sqrt(max(0,1-d/4)) | |
59 | if longflag==sweepflag: | |
60 | d*=-1 | |
61 | O=[(B[0]+A[0])/2+d*k[0],(B[1]+A[1])/2+d*k[1]] | |
62 | OA=[A[0]-O[0],A[1]-O[1]] | |
63 | OB=[B[0]-O[0],B[1]-O[1]] | |
64 | start=acos(OA[0]/norm(OA)) | |
65 | if OA[1]<0: | |
66 | start*=-1 | |
67 | end=acos(OB[0]/norm(OB)) | |
68 | if OB[1]<0: | |
69 | end*=-1 | |
70 | ||
71 | if sweepflag and start>end: | |
72 | end +=2*pi | |
73 | if (not sweepflag) and start<end: | |
74 | end -=2*pi | |
75 | ||
76 | NbSectors=int(abs(start-end)*2/pi)+1 | |
77 | dTeta=(end-start)/NbSectors | |
78 | #v=dTeta*2/pi*0.552 | |
79 | #v=dTeta*2/pi*4*(sqrt(2)-1)/3 | |
80 | v = 4*tan(dTeta/4)/3 | |
81 | #if not sweepflag: | |
82 | # v*=-1 | |
83 | p=[] | |
84 | for i in range(0,NbSectors+1,1): | |
85 | angle=start+i*dTeta | |
86 | v1=[O[0]+cos(angle)-(-v)*sin(angle),O[1]+sin(angle)+(-v)*cos(angle)] | |
87 | pt=[O[0]+cos(angle) ,O[1]+sin(angle) ] | |
88 | v2=[O[0]+cos(angle)- v *sin(angle),O[1]+sin(angle)+ v *cos(angle)] | |
89 | p.append([v1,pt,v2]) | |
90 | p[ 0][0]=p[ 0][1][:] | |
91 | p[-1][2]=p[-1][1][:] | |
92 | ||
93 | mat=matprod((rotmat(teta),[[rx,0],[0,ry]],rotmat(-teta))) | |
94 | for pts in p: | |
95 | applymat(mat, pts[0]) | |
96 | applymat(mat, pts[1]) | |
97 | applymat(mat, pts[2]) | |
98 | return(p) | |
99 | ||
100 | def CubicSuperPath(simplepath): | |
101 | csp = [] | |
102 | subpath = -1 | |
103 | subpathstart = [] | |
104 | last = [] | |
105 | lastctrl = [] | |
106 | for s in simplepath: | |
107 | cmd, params = s | |
108 | if cmd == 'M': | |
109 | if last: | |
110 | csp[subpath].append([lastctrl[:],last[:],last[:]]) | |
111 | subpath += 1 | |
112 | csp.append([]) | |
113 | subpathstart = params[:] | |
114 | last = params[:] | |
115 | lastctrl = params[:] | |
116 | elif cmd == 'L': | |
117 | csp[subpath].append([lastctrl[:],last[:],last[:]]) | |
118 | last = params[:] | |
119 | lastctrl = params[:] | |
120 | elif cmd == 'C': | |
121 | csp[subpath].append([lastctrl[:],last[:],params[:2]]) | |
122 | last = params[-2:] | |
123 | lastctrl = params[2:4] | |
124 | elif cmd == 'Q': | |
125 | q0=last[:] | |
126 | q1=params[0:2] | |
127 | q2=params[2:4] | |
128 | x0= q0[0] | |
129 | x1=1./3*q0[0]+2./3*q1[0] | |
130 | x2= 2./3*q1[0]+1./3*q2[0] | |
131 | x3= q2[0] | |
132 | y0= q0[1] | |
133 | y1=1./3*q0[1]+2./3*q1[1] | |
134 | y2= 2./3*q1[1]+1./3*q2[1] | |
135 | y3= q2[1] | |
136 | csp[subpath].append([lastctrl[:],[x0,y0],[x1,y1]]) | |
137 | last = [x3,y3] | |
138 | lastctrl = [x2,y2] | |
139 | elif cmd == 'A': | |
140 | arcp=ArcToPath(last[:],params[:]) | |
141 | arcp[ 0][0]=lastctrl[:] | |
142 | last=arcp[-1][1] | |
143 | lastctrl = arcp[-1][0] | |
144 | csp[subpath]+=arcp[:-1] | |
145 | elif cmd == 'Z': | |
146 | csp[subpath].append([lastctrl[:],last[:],last[:]]) | |
147 | last = subpathstart[:] | |
148 | lastctrl = subpathstart[:] | |
149 | #append final superpoint | |
150 | csp[subpath].append([lastctrl[:],last[:],last[:]]) | |
151 | return csp | |
152 | ||
153 | def unCubicSuperPath(csp): | |
154 | a = [] | |
155 | for subpath in csp: | |
156 | if subpath: | |
157 | a.append(['M',subpath[0][1][:]]) | |
158 | for i in range(1,len(subpath)): | |
159 | a.append(['C',subpath[i-1][2][:] + subpath[i][0][:] + subpath[i][1][:]]) | |
160 | return a | |
161 | ||
162 | def parsePath(d): | |
163 | return CubicSuperPath(simplepath.parsePath(d)) | |
164 | ||
165 | def formatPath(p): | |
166 | return simplepath.formatPath(unCubicSuperPath(p)) | |
167 | ||
168 | ||
169 | # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 |