Code

a151084eb39b41bcf4bb7a60aff430c8bd5072c9
[inkscape.git] / share / extensions / cubicsuperpath.py
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 class SuperSubpath(list):
26     def __init__(self, items=[]):
27         self.closed = False
28         list.__init__(self, items)
29     def close(self, state=True):
30         self.closed = state
32 def matprod(mlist):
33     prod=mlist[0]
34     for m in mlist[1:]:
35         a00=prod[0][0]*m[0][0]+prod[0][1]*m[1][0]
36         a01=prod[0][0]*m[0][1]+prod[0][1]*m[1][1]
37         a10=prod[1][0]*m[0][0]+prod[1][1]*m[1][0]
38         a11=prod[1][0]*m[0][1]+prod[1][1]*m[1][1]
39         prod=[[a00,a01],[a10,a11]]
40     return prod
41 def rotmat(teta):
42     return [[cos(teta),-sin(teta)],[sin(teta),cos(teta)]]
43 def applymat(mat, pt):
44     x=mat[0][0]*pt[0]+mat[0][1]*pt[1]
45     y=mat[1][0]*pt[0]+mat[1][1]*pt[1]
46     pt[0]=x
47     pt[1]=y
48 def norm(pt):
49     return sqrt(pt[0]*pt[0]+pt[1]*pt[1])
51 def ArcToPath(p1,params):
52     A=p1[:]
53     rx,ry,teta,longflag,sweepflag,x2,y2=params[:]
54     B=[x2,y2]
55     if rx==0 or ry==0:
56         return([[A,A,A],[B,B,B]])
57     mat=matprod((rotmat(teta),[[1/rx,0],[0,1/ry]],rotmat(-teta)))
58     applymat(mat, A)
59     applymat(mat, B)
60     k=[-(B[1]-A[1]),B[0]-A[0]]
61     d=k[0]*k[0]+k[1]*k[1]
62     k[0]/=sqrt(d)
63     k[1]/=sqrt(d)
64     d=sqrt(max(0,1-d/4))
65     if longflag==sweepflag:
66         d*=-1
67     O=[(B[0]+A[0])/2+d*k[0],(B[1]+A[1])/2+d*k[1]]
68     OA=[A[0]-O[0],A[1]-O[1]]
69     OB=[B[0]-O[0],B[1]-O[1]]
70     start=acos(OA[0]/norm(OA))
71     if OA[1]<0:
72         start*=-1
73     end=acos(OB[0]/norm(OB))
74     if OB[1]<0:
75         end*=-1
77     if sweepflag and start>end:
78         end +=2*pi
79     if (not sweepflag) and start<end:
80         end -=2*pi
82     NbSectors=int(abs(start-end)*2/pi)+1
83     dTeta=(end-start)/NbSectors
84     #v=dTeta*2/pi*0.552
85     v=dTeta*2/pi*4*(sqrt(2)-1)/3
86     #if not sweepflag:
87     #   v*=-1
88     p=[]
89     for i in range(0,NbSectors+1,1):
90         angle=start+i*dTeta
91         v1=[O[0]+cos(angle)-(-v)*sin(angle),O[1]+sin(angle)+(-v)*cos(angle)]
92         pt=[O[0]+cos(angle)                ,O[1]+sin(angle)                ]
93         v2=[O[0]+cos(angle)-  v *sin(angle),O[1]+sin(angle)+  v *cos(angle)]
94         p.append([v1,pt,v2])
95     p[ 0][0]=p[ 0][1][:]
96     p[-1][2]=p[-1][1][:]
98     mat=matprod((rotmat(teta),[[rx,0],[0,ry]],rotmat(-teta)))
99     for pts in p:
100         applymat(mat, pts[0])
101         applymat(mat, pts[1])
102         applymat(mat, pts[2])
103     return(p)
104     
105 def CubicSuperPath(simplepath):
106     csp = []
107     subpath = -1
108     subpathstart = []
109     last = []
110     lastctrl = []
111     for s in simplepath:
112         cmd, params = s        
113         if cmd == 'M':
114             subpath += 1
115             csp.append(SuperSubpath())
116             subpathstart =  params[:]
117             last = params[:]
118             lastctrl = params[:]
119         elif cmd == 'L':
120             csp[subpath].append([lastctrl[:],last[:],last[:]])
121             last = params[:]
122             lastctrl = params[:]
123         elif cmd == 'C':
124             csp[subpath].append([lastctrl[:],last[:],params[:2]])
125             last = params[-2:]
126             lastctrl = params[2:4]
127         elif cmd == 'Q':
128             q0=last[:]
129             q1=params[0:1]
130             q2=params[2:3]
131             x0=    q0[0]
132             x1=1/3*q0[0]+2/3*q1[0]
133             x2=          2/3*q1[0]+1/3*q2[0]
134             x3=                        q2[0]
135             y0=    q0[1]
136             y1=1/3*q0[1]+2/3*q1[1]
137             y2=          2/3*q1[1]+1/3*q2[1]
138             y3=                        q2[1]
139             csp[subpath].append([lastctrl[:][x0,y0][x1,y1]])
140             last = [x3,y3]
141             lastctrl = [x2,y2]
142         elif cmd == 'A':
143             arcp=ArcToPath(last[:],params[:])
144             arcp[ 0][0]=lastctrl[:]
145             last=arcp[-1][1]
146             lastctrl = arcp[-1][0]
147             csp[subpath]+=arcp[:-1]
148         elif cmd == 'Z':
149             csp[subpath].close()
150             last = subpathstart[:]
151             lastctrl = subpathstart[:]
152     return csp    
154 def unCubicSuperPath(csp):
155     a = []
156     for subpath in csp:
157         if subpath:
158             a.append(['M',subpath[0][1][:]])
159             for i in range(1,len(subpath)):
160                 a.append(['C',subpath[i-1][2][:] + subpath[i][0][:] + subpath[i][1][:]])
161             try:
162                 if subpath.closed:
163                     a.append(['Z',[]])
164             except:
165                 pass
166     return a
168 def parsePath(d):
169     return CubicSuperPath(simplepath.parsePath(d))
171 def formatPath(p):
172     return simplepath.formatPath(unCubicSuperPath(p))