simpletransform.py revision 6a39552e18be9951d0468bcad8778110999245ca
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc#!/usr/bin/env python
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc'''
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcCopyright (C) 2006 Jean-Francois Barraud, barraud@math.univ-lille1.fr
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcThis program is free software; you can redistribute it and/or modify
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcit under the terms of the GNU General Public License as published by
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcthe Free Software Foundation; either version 2 of the License, or
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc(at your option) any later version.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcThis program is distributed in the hope that it will be useful,
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcbut WITHOUT ANY WARRANTY; without even the implied warranty of
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcGNU General Public License for more details.
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcYou should have received a copy of the GNU General Public License
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcalong with this program; if not, write to the Free Software
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcFoundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcbarraud@math.univ-lille1.fr
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcThis code defines several functions to make handling of transform
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcattribute easier.
d62bc4badc1c1f1549c961cfb8b420e650e1272byz'''
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcimport inkex, cubicsuperpath, bezmisc, simplestyle
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcimport copy, math, re
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxcdef parseTransform(transf,mat=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]):
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if transf=="" or transf==None:
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc return(mat)
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc stransf = transf.strip()
d62bc4badc1c1f1549c961cfb8b420e650e1272byz result=re.match("(translate|scale|rotate|skewX|skewY|matrix)\s*\(([^)]*)\)\s*,?",stransf)
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh#-- translate --
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc if result.group(1)=="translate":
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh args=result.group(2).replace(',',' ').split()
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh dx=float(args[0])
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if len(args)==1:
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh dy=0.0
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh else:
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh dy=float(args[1])
f595a68a3b8953a12aa778c2abd7642df8da8c3ayz matrix=[[1,0,dx],[0,1,dy]]
0ba2cbe97e0678a691742f98d2532caed0a2c4aaxc#-- scale --
d62bc4badc1c1f1549c961cfb8b420e650e1272byz if result.group(1)=="scale":
f595a68a3b8953a12aa778c2abd7642df8da8c3ayz args=result.group(2).replace(',',' ').split()
d62bc4badc1c1f1549c961cfb8b420e650e1272byz sx=float(args[0])
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if len(args)==1:
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh sy=sx
d62bc4badc1c1f1549c961cfb8b420e650e1272byz else:
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini sy=float(args[1])
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini matrix=[[sx,0,0],[0,sy,0]]
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini#-- rotate --
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini if result.group(1)=="rotate":
bcb5c89da22515e2ccf139578bad3caebcd716adSowmini Varadhan args=result.group(2).replace(',',' ').split()
bcb5c89da22515e2ccf139578bad3caebcd716adSowmini Varadhan a=float(args[0])*math.pi/180
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh if len(args)==1:
afdda45f890ee5dfc86e5131a30b11b354d51633Vasumathi Sundaram - Sun Microsystems cx,cy=(0.0,0.0)
afdda45f890ee5dfc86e5131a30b11b354d51633Vasumathi Sundaram - Sun Microsystems else:
afdda45f890ee5dfc86e5131a30b11b354d51633Vasumathi Sundaram - Sun Microsystems cx,cy=map(float,args[1:])
d62bc4badc1c1f1549c961cfb8b420e650e1272byz matrix=[[math.cos(a),-math.sin(a),cx],[math.sin(a),math.cos(a),cy]]
d62bc4badc1c1f1549c961cfb8b420e650e1272byz matrix=composeTransform(matrix,[[1,0,-cx],[0,1,-cy]])
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini#-- skewX --
d62bc4badc1c1f1549c961cfb8b420e650e1272byz if result.group(1)=="skewX":
d62bc4badc1c1f1549c961cfb8b420e650e1272byz a=float(result.group(2))*math.pi/180
d62bc4badc1c1f1549c961cfb8b420e650e1272byz matrix=[[1,math.tan(a),0],[0,1,0]]
d62bc4badc1c1f1549c961cfb8b420e650e1272byz#-- skewY --
d62bc4badc1c1f1549c961cfb8b420e650e1272byz if result.group(1)=="skewY":
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini a=float(result.group(2))*math.pi/180
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini matrix=[[1,0,0],[math.tan(a),1,0]]
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini#-- matrix --
6b9e797c2ea518518cb2b57895991d8bdaa167fesowmini if result.group(1)=="matrix":
afdda45f890ee5dfc86e5131a30b11b354d51633Vasumathi Sundaram - Sun Microsystems a11,a21,a12,a22,v1,v2=result.group(2).replace(',',' ').split()
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh matrix=[[float(a11),float(a12),float(v1)], [float(a21),float(a22),float(v2)]]
d62bc4badc1c1f1549c961cfb8b420e650e1272byz
d62bc4badc1c1f1549c961cfb8b420e650e1272byz matrix=composeTransform(mat,matrix)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz if result.end() < len(stransf):
d62bc4badc1c1f1549c961cfb8b420e650e1272byz return(parseTransform(stransf[result.end():], matrix))
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini else:
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini return matrix
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowminidef formatTransform(mat):
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini 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]))
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini
d62bc4badc1c1f1549c961cfb8b420e650e1272byzdef composeTransform(M1,M2):
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini a11 = M1[0][0]*M2[0][0] + M1[0][1]*M2[1][0]
6b9e797c2ea518518cb2b57895991d8bdaa167fesowmini a12 = M1[0][0]*M2[0][1] + M1[0][1]*M2[1][1]
6b9e797c2ea518518cb2b57895991d8bdaa167fesowmini a21 = M1[1][0]*M2[0][0] + M1[1][1]*M2[1][0]
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh a22 = M1[1][0]*M2[0][1] + M1[1][1]*M2[1][1]
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh
d62bc4badc1c1f1549c961cfb8b420e650e1272byz v1 = M1[0][0]*M2[0][2] + M1[0][1]*M2[1][2] + M1[0][2]
d62bc4badc1c1f1549c961cfb8b420e650e1272byz v2 = M1[1][0]*M2[0][2] + M1[1][1]*M2[1][2] + M1[1][2]
d62bc4badc1c1f1549c961cfb8b420e650e1272byz return [[a11,a12,v1],[a21,a22,v2]]
d62bc4badc1c1f1549c961cfb8b420e650e1272byz
d62bc4badc1c1f1549c961cfb8b420e650e1272byzdef applyTransformToNode(mat,node):
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini m=parseTransform(node.get("transform"))
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini newtransf=formatTransform(composeTransform(mat,m))
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini node.set("transform", newtransf)
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowminidef applyTransformToPoint(mat,pt):
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini x = mat[0][0]*pt[0] + mat[0][1]*pt[1] + mat[0][2]
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini y = mat[1][0]*pt[0] + mat[1][1]*pt[1] + mat[1][2]
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini pt[0]=x
d62bc4badc1c1f1549c961cfb8b420e650e1272byz pt[1]=y
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowminidef applyTransformToPath(mat,path):
6b9e797c2ea518518cb2b57895991d8bdaa167fesowmini for comp in path:
6b9e797c2ea518518cb2b57895991d8bdaa167fesowmini for ctl in comp:
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini for pt in ctl:
bcb5c89da22515e2ccf139578bad3caebcd716adSowmini Varadhan applyTransformToPoint(mat,pt)
3fd94f8c011031b38162a1db3b554de4371c167fam
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowminidef fuseTransform(node):
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini if node.get('d')==None:
bcb5c89da22515e2ccf139578bad3caebcd716adSowmini Varadhan #FIXME: how do you raise errors?
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini raise AssertionError, 'can not fuse "transform" of elements that have no "d" attribute'
bcb5c89da22515e2ccf139578bad3caebcd716adSowmini Varadhan t = node.get("transform")
bcb5c89da22515e2ccf139578bad3caebcd716adSowmini Varadhan if t == None:
bcb5c89da22515e2ccf139578bad3caebcd716adSowmini Varadhan return
bcb5c89da22515e2ccf139578bad3caebcd716adSowmini Varadhan m = parseTransform(t)
bcb5c89da22515e2ccf139578bad3caebcd716adSowmini Varadhan d = node.get('d')
3bc21d0a9c7b31b1132c254e389a4114c23bcf00Aruna Ramakrishna - Sun Microsystems p = cubicsuperpath.parsePath(d)
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini applyTransformToPath(m,p)
3bc21d0a9c7b31b1132c254e389a4114c23bcf00Aruna Ramakrishna - Sun Microsystems node.set('d', cubicsuperpath.formatPath(p))
4045d94132614e1de2073685a6cdd4fbd86bec33sowmini del node.attrib["transform"]
bcb5c89da22515e2ccf139578bad3caebcd716adSowmini Varadhan
bcb5c89da22515e2ccf139578bad3caebcd716adSowmini Varadhan####################################################################
3bc21d0a9c7b31b1132c254e389a4114c23bcf00Aruna Ramakrishna - Sun Microsystems##-- Some functions to compute a rough bbox of a given list of objects.
3bc21d0a9c7b31b1132c254e389a4114c23bcf00Aruna Ramakrishna - Sun Microsystems##-- this should be shipped out in an separate file...
d62bc4badc1c1f1549c961cfb8b420e650e1272byz
d62bc4badc1c1f1549c961cfb8b420e650e1272byzdef boxunion(b1,b2):
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini if b1 is None:
3bc21d0a9c7b31b1132c254e389a4114c23bcf00Aruna Ramakrishna - Sun Microsystems return b2
3bc21d0a9c7b31b1132c254e389a4114c23bcf00Aruna Ramakrishna - Sun Microsystems elif b2 is None:
3bc21d0a9c7b31b1132c254e389a4114c23bcf00Aruna Ramakrishna - Sun Microsystems return b1
3bc21d0a9c7b31b1132c254e389a4114c23bcf00Aruna Ramakrishna - Sun Microsystems else:
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini return((min(b1[0],b2[0]), max(b1[1],b2[1]), min(b1[2],b2[2]), max(b1[3],b2[3])))
3bc21d0a9c7b31b1132c254e389a4114c23bcf00Aruna Ramakrishna - Sun Microsystems
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowminidef roughBBox(path):
3bc21d0a9c7b31b1132c254e389a4114c23bcf00Aruna Ramakrishna - Sun Microsystems xmin,xMax,ymin,yMax = path[0][0][0][0],path[0][0][0][0],path[0][0][0][1],path[0][0][0][1]
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dh for pathcomp in path:
3bc21d0a9c7b31b1132c254e389a4114c23bcf00Aruna Ramakrishna - Sun Microsystems for ctl in pathcomp:
4045d94132614e1de2073685a6cdd4fbd86bec33sowmini for pt in ctl:
bcb5c89da22515e2ccf139578bad3caebcd716adSowmini Varadhan xmin = min(xmin,pt[0])
bcb5c89da22515e2ccf139578bad3caebcd716adSowmini Varadhan xMax = max(xMax,pt[0])
bcb5c89da22515e2ccf139578bad3caebcd716adSowmini Varadhan ymin = min(ymin,pt[1])
bcb5c89da22515e2ccf139578bad3caebcd716adSowmini Varadhan yMax = max(yMax,pt[1])
bcb5c89da22515e2ccf139578bad3caebcd716adSowmini Varadhan return xmin,xMax,ymin,yMax
6b9e797c2ea518518cb2b57895991d8bdaa167fesowmini
f4b3ec61df05330d25f55a36b975b4d7519fdeb1dhdef computeBBox(aList,mat=[[1,0,0],[0,1,0]]):
d62bc4badc1c1f1549c961cfb8b420e650e1272byz bbox=None
d62bc4badc1c1f1549c961cfb8b420e650e1272byz for node in aList:
d62bc4badc1c1f1549c961cfb8b420e650e1272byz m = parseTransform(node.get('transform'))
d62bc4badc1c1f1549c961cfb8b420e650e1272byz m = composeTransform(mat,m)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz #TODO: text not supported!
d62bc4badc1c1f1549c961cfb8b420e650e1272byz d = None
d62bc4badc1c1f1549c961cfb8b420e650e1272byz if node.get("d"):
d62bc4badc1c1f1549c961cfb8b420e650e1272byz d = node.get('d')
d62bc4badc1c1f1549c961cfb8b420e650e1272byz elif node.get('points'):
d62bc4badc1c1f1549c961cfb8b420e650e1272byz d = 'M' + node.get('points')
d62bc4badc1c1f1549c961cfb8b420e650e1272byz elif node.tag in [ inkex.addNS('rect','svg'), 'rect' ]:
d62bc4badc1c1f1549c961cfb8b420e650e1272byz d = 'M' + node.get('x', '0') + ',' + node.get('y', '0') + \
d62bc4badc1c1f1549c961cfb8b420e650e1272byz 'h' + node.get('width') + 'v' + node.get('height') + \
d62bc4badc1c1f1549c961cfb8b420e650e1272byz 'h-' + node.get('width')
d62bc4badc1c1f1549c961cfb8b420e650e1272byz elif node.tag in [ inkex.addNS('line','svg'), 'line' ]:
d62bc4badc1c1f1549c961cfb8b420e650e1272byz d = 'M' + node.get('x1') + ',' + node.get('y1') + \
d62bc4badc1c1f1549c961cfb8b420e650e1272byz ' ' + node.get('x2') + ',' + node.get('y2')
d62bc4badc1c1f1549c961cfb8b420e650e1272byz elif node.tag in [ inkex.addNS('circle','svg'), 'circle', \
d62bc4badc1c1f1549c961cfb8b420e650e1272byz inkex.addNS('ellipse','svg'), 'ellipse' ]:
d62bc4badc1c1f1549c961cfb8b420e650e1272byz rx = node.get('r')
d62bc4badc1c1f1549c961cfb8b420e650e1272byz if rx is not None:
d62bc4badc1c1f1549c961cfb8b420e650e1272byz ry = rx
d62bc4badc1c1f1549c961cfb8b420e650e1272byz else:
d62bc4badc1c1f1549c961cfb8b420e650e1272byz rx = node.get('rx')
d62bc4badc1c1f1549c961cfb8b420e650e1272byz ry = node.get('ry')
d62bc4badc1c1f1549c961cfb8b420e650e1272byz cx = float(node.get('cx', '0'))
d62bc4badc1c1f1549c961cfb8b420e650e1272byz cy = float(node.get('cy', '0'))
d62bc4badc1c1f1549c961cfb8b420e650e1272byz x1 = cx - float(rx)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz x2 = cx + float(rx)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz d = 'M %f %f ' % (x1, cy) + \
d62bc4badc1c1f1549c961cfb8b420e650e1272byz 'A' + rx + ',' + ry + ' 0 1 0 %f,%f' % (x2, cy) + \
d62bc4badc1c1f1549c961cfb8b420e650e1272byz 'A' + rx + ',' + ry + ' 0 1 0 %f,%f' % (x1, cy)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz
d62bc4badc1c1f1549c961cfb8b420e650e1272byz if d is not None:
d62bc4badc1c1f1549c961cfb8b420e650e1272byz p = cubicsuperpath.parsePath(d)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz applyTransformToPath(m,p)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz bbox=boxunion(roughBBox(p),bbox)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz
d62bc4badc1c1f1549c961cfb8b420e650e1272byz elif node.tag == inkex.addNS('use','svg') or node.tag=='use':
d62bc4badc1c1f1549c961cfb8b420e650e1272byz refid=node.get(inkex.addNS('href','xlink'))
d62bc4badc1c1f1549c961cfb8b420e650e1272byz path = '//*[@id="%s"]' % refid[1:]
d62bc4badc1c1f1549c961cfb8b420e650e1272byz refnode = node.xpath(path)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz bbox=boxunion(computeBBox(refnode,m),bbox)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz
d62bc4badc1c1f1549c961cfb8b420e650e1272byz bbox=boxunion(computeBBox(node,m),bbox)
d62bc4badc1c1f1549c961cfb8b420e650e1272byz return bbox
d62bc4badc1c1f1549c961cfb8b420e650e1272byz
d62bc4badc1c1f1549c961cfb8b420e650e1272byz
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99
e7801d59e8ceda0cde8ebdfdddd7582ee2ea96efsowmini