3
Copyright (C) 2006 Jean-Francois Barraud, barraud@math.univ-lille1.fr
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation; either version 2 of the License, or
8
(at your option) any later version.
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
barraud@math.univ-lille1.fr
20
This code defines several functions to make handling of transform
23
import inkex, cubicsuperpath, bezmisc, simplestyle
26
def parseTransform(transf,mat=[[1.0,0.0,0.0],[0.0,1.0,0.0]]):
27
if transf=="" or transf==None:
29
result=re.match("(translate|scale|rotate|skewX|skewY|matrix)\(([^)]*)\)",transf)
31
if result.group(1)=="translate":
32
args=result.group(2).split(",")
38
matrix=[[1,0,dx],[0,1,dy]]
40
if result.groups(1)=="scale":
41
args=result.group(2).split(",")
47
matrix=[[sx,0,0],[0,sy,0]]
49
if result.groups(1)=="rotate":
50
args=result.group(2).split(",")
51
a=float(args[0])*math.pi/180
56
matrix=[[math.cos(a),-math.sin(a),cx],[math.sin(a),math.cos(a),cy]]
58
if result.groups(1)=="skewX":
59
a=float(result.group(2))*math.pi/180
60
matrix=[[1,math.tan(a),0],[0,1,0]]
62
if result.groups(1)=="skewX":
63
a=float(result.group(2))*math.pi/180
64
matrix=[[1,0,0],[math.tan(a),1,0]]
66
if result.group(1)=="matrix":
67
a11,a21,a12,a22,v1,v2=result.group(2).split(",")
68
matrix=[[float(a11),float(a12),float(v1)],[float(a21),float(a22),float(v2)]]
70
matrix=composeTransform(mat,matrix)
71
if result.end()<len(transf):
72
return(parseTransform(transf[result.end():],matrix))
76
def formatTransform(mat):
77
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]))
79
def composeTransform(M1,M2):
80
a11=M1[0][0]*M2[0][0]+M1[0][1]*M2[1][0]
81
a12=M1[0][0]*M2[0][1]+M1[0][1]*M2[1][1]
82
a21=M1[1][0]*M2[0][0]+M1[1][1]*M2[1][0]
83
a22=M1[1][0]*M2[0][1]+M1[1][1]*M2[1][1]
85
v1=M1[0][0]*M2[0][2]+M1[0][1]*M2[1][2]+M1[0][2]
86
v2=M1[1][0]*M2[0][2]+M1[1][1]*M2[1][2]+M1[1][2]
87
return [[a11,a12,v1],[a21,a22,v2]]
89
def applyTransformToNode(mat,node):
90
m=parseTransform(node.get("transform"))
91
newtransf=formatTransform(composeTransform(mat,m))
92
node.set("transform", newtransf)
94
def applyTransformToPoint(mat,pt):
95
x=mat[0][0]*pt[0]+mat[0][1]*pt[1]+mat[0][2]
96
y=mat[1][0]*pt[0]+mat[1][1]*pt[1]+mat[1][2]
100
def applyTransformToPath(mat,path):
104
applyTransformToPoint(mat,pt)
106
def fuseTransform(node):
107
if node.get('d')==None:
108
#FIX ME: how do you raise errors?
109
raise AssertionError, 'can not fuse "transform" of elements that have no "d" attribute'
110
t = node.get("transform")
113
m = parseTransform(t)
115
p = cubicsuperpath.parsePath(d)
116
applyTransformToPath(m,p)
117
node.set('d', cubicsuperpath.formatPath(p))
118
del node.attrib["transform"]
120
####################################################################
121
##-- Some functions to compute a rough bbox of a given list of objects.
122
##-- this should be shipped out in an separate file...
130
return((min(b1[0],b2[0]),max(b1[1],b2[1]),min(b1[2],b2[2]),max(b1[3],b2[3])))
133
xmin,xMax,ymin,yMax=path[0][0][0][0],path[0][0][0][0],path[0][0][0][1],path[0][0][0][1]
134
for pathcomp in path:
141
return xmin,xMax,ymin,yMax
143
def computeBBox(aList,mat=[[1,0,0],[0,1,0]]):
146
m = parseTransform(node.get('transform'))
147
m = composeTransform(mat,m)
148
#TODO: text not supported!
151
p = cubicsuperpath.parsePath(d)
152
applyTransformToPath(m,p)
153
bbox=boxunion(roughBBox(p),bbox)
155
if node.tag == inkex.addNS('use','svg') or node.tag=='use':
156
refid=node.get(inkex.addNS('href','xlink'))
157
path = '//*[@id="%s"]' % refid[1:]
158
refnode = node.getroottree().xpath(path, namespaces=inkex.NSS)
159
bbox=boxunion(computeBBox(refnode,m),bbox)
161
bbox=boxunion(computeBBox(node,m),bbox)
3
Copyright (C) 2006 Jean-Francois Barraud, barraud@math.univ-lille1.fr
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation; either version 2 of the License, or
8
(at your option) any later version.
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
barraud@math.univ-lille1.fr
20
This code defines several functions to make handling of transform
23
import inkex, cubicsuperpath, bezmisc, simplestyle
26
def parseTransform(transf,mat=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]):
27
if transf=="" or transf==None:
29
stransf = transf.strip()
30
result=re.match("(translate|scale|rotate|skewX|skewY|matrix)\s*\(([^)]*)\)\s*,?",stransf)
32
if result.group(1)=="translate":
33
args=result.group(2).replace(',',' ').split()
39
matrix=[[1,0,dx],[0,1,dy]]
41
if result.group(1)=="scale":
42
args=result.group(2).replace(',',' ').split()
48
matrix=[[sx,0,0],[0,sy,0]]
50
if result.group(1)=="rotate":
51
args=result.group(2).replace(',',' ').split()
52
a=float(args[0])*math.pi/180
56
cx,cy=map(float,args[1:])
57
matrix=[[math.cos(a),-math.sin(a),cx],[math.sin(a),math.cos(a),cy]]
59
if result.group(1)=="skewX":
60
a=float(result.group(2))*math.pi/180
61
matrix=[[1,math.tan(a),0],[0,1,0]]
63
if result.group(1)=="skewY":
64
a=float(result.group(2))*math.pi/180
65
matrix=[[1,0,0],[math.tan(a),1,0]]
67
if result.group(1)=="matrix":
68
a11,a21,a12,a22,v1,v2=result.group(2).replace(',',' ').split()
69
matrix=[[float(a11),float(a12),float(v1)], [float(a21),float(a22),float(v2)]]
71
matrix=composeTransform(mat,matrix)
72
if result.end() < len(stransf):
73
return(parseTransform(stransf[result.end():], matrix))
77
def formatTransform(mat):
78
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]))
80
def composeTransform(M1,M2):
81
a11 = M1[0][0]*M2[0][0] + M1[0][1]*M2[1][0]
82
a12 = M1[0][0]*M2[0][1] + M1[0][1]*M2[1][1]
83
a21 = M1[1][0]*M2[0][0] + M1[1][1]*M2[1][0]
84
a22 = M1[1][0]*M2[0][1] + M1[1][1]*M2[1][1]
86
v1 = M1[0][0]*M2[0][2] + M1[0][1]*M2[1][2] + M1[0][2]
87
v2 = M1[1][0]*M2[0][2] + M1[1][1]*M2[1][2] + M1[1][2]
88
return [[a11,a12,v1],[a21,a22,v2]]
90
def applyTransformToNode(mat,node):
91
m=parseTransform(node.get("transform"))
92
newtransf=formatTransform(composeTransform(mat,m))
93
node.set("transform", newtransf)
95
def applyTransformToPoint(mat,pt):
96
x = mat[0][0]*pt[0] + mat[0][1]*pt[1] + mat[0][2]
97
y = mat[1][0]*pt[0] + mat[1][1]*pt[1] + mat[1][2]
101
def applyTransformToPath(mat,path):
105
applyTransformToPoint(mat,pt)
107
def fuseTransform(node):
108
if node.get('d')==None:
109
#FIXME: how do you raise errors?
110
raise AssertionError, 'can not fuse "transform" of elements that have no "d" attribute'
111
t = node.get("transform")
114
m = parseTransform(t)
116
p = cubicsuperpath.parsePath(d)
117
applyTransformToPath(m,p)
118
node.set('d', cubicsuperpath.formatPath(p))
119
del node.attrib["transform"]
121
####################################################################
122
##-- Some functions to compute a rough bbox of a given list of objects.
123
##-- this should be shipped out in an separate file...
131
return((min(b1[0],b2[0]), max(b1[1],b2[1]), min(b1[2],b2[2]), max(b1[3],b2[3])))
134
xmin,xMax,ymin,yMax = path[0][0][0][0],path[0][0][0][0],path[0][0][0][1],path[0][0][0][1]
135
for pathcomp in path:
138
xmin = min(xmin,pt[0])
139
xMax = max(xMax,pt[0])
140
ymin = min(ymin,pt[1])
141
yMax = max(yMax,pt[1])
142
return xmin,xMax,ymin,yMax
144
def computeBBox(aList,mat=[[1,0,0],[0,1,0]]):
147
m = parseTransform(node.get('transform'))
148
m = composeTransform(mat,m)
149
#TODO: text not supported!
152
p = cubicsuperpath.parsePath(d)
153
applyTransformToPath(m,p)
154
bbox=boxunion(roughBBox(p),bbox)
156
elif node.tag == inkex.addNS('rect','svg') or node.tag=='rect':
157
w = float(node.get('width'))/2.
158
h = float(node.get('height'))/2.
159
x = float(node.get('x'))
160
y = float(node.get('y'))
162
applyTransformToPoint(mat,C)
163
xmin = C[0] - abs(m[0][0]) * w - abs(m[0][1]) * h
164
xmax = C[0] + abs(m[0][0]) * w + abs(m[0][1]) * h
165
ymin = C[1] - abs(m[1][0]) * w - abs(m[1][1]) * h
166
ymax = C[1] + abs(m[1][0]) * w + abs(m[1][1]) * h
167
bbox = xmin,xmax,ymin,ymax
169
elif node.tag == inkex.addNS('use','svg') or node.tag=='use':
170
refid=node.get(inkex.addNS('href','xlink'))
171
path = '//*[@id="%s"]' % refid[1:]
172
refnode = node.xpath(path)
173
bbox=boxunion(computeBBox(refnode,m),bbox)
175
bbox=boxunion(computeBBox(node,m),bbox)
179
# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99