index f434d80ed76c722fe47992596c59d28bf2c448ef..b2f6a0e96e19d1e2400ef510ffd98f6ffa29d726 100644 (file)
-#!/usr/bin/env python\r
-'''\r
-Copyright (C) 2006 Jean-Francois Barraud, barraud@math.univ-lille1.fr\r
-\r
-This program is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-This program is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with this program; if not, write to the Free Software\r
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
-barraud@math.univ-lille1.fr\r
-\r
-This code defines several functions to make handling of transform\r
-attribute easier.\r
-'''\r
-import inkex, cubicsuperpath, bezmisc, simplestyle\r
-import copy, math, re\r
-\r
-def parseTransform(transf,mat=[[1.0,0.0,0.0],[0.0,1.0,0.0]]):\r
- if transf=="" or transf==None:\r
- return(mat)\r
- result=re.match("(translate|scale|rotate|skewX|skewY|matrix)\(([^)]*)\)",transf)\r
-#-- translate --\r
- if result.group(1)=="translate":\r
- args=result.group(2).split(",")\r
- dx=float(args[0])\r
- if len(args)==1:\r
- dy=0.0\r
- else:\r
- dy=float(args[1])\r
- matrix=[[1,0,dx],[0,1,dy]]\r
-#-- scale --\r
- if result.groups(1)=="scale":\r
- args=result.group(2).split(",")\r
- sx=float(args[0])\r
- if len(args)==1:\r
- sy=sx\r
- else:\r
- sy=float(args[1])\r
- matrix=[[sx,0,0],[0,sy,0]]\r
-#-- rotate --\r
- if result.groups(1)=="rotate":\r
- args=result.group(2).split(",")\r
- a=float(args[0])*math.pi/180\r
- if len(args)==1:\r
- cx,cy=(0.0,0.0)\r
- else:\r
- cx,cy=args[1:]\r
- matrix=[[math.cos(a),-math.sin(a),cx],[math.sin(a),math.cos(a),cy]]\r
-#-- skewX --\r
- if result.groups(1)=="skewX":\r
- a=float(result.group(2))*math.pi/180\r
- matrix=[[1,math.tan(a),0],[0,1,0]]\r
-#-- skewX --\r
- if result.groups(1)=="skewX":\r
- a=float(result.group(2))*math.pi/180\r
- matrix=[[1,0,0],[math.tan(a),1,0]]\r
-#-- matrix --\r
- if result.group(1)=="matrix":\r
- a11,a21,a12,a22,v1,v2=result.group(2).split(",")\r
- matrix=[[float(a11),float(a12),float(v1)],[float(a21),float(a22),float(v2)]]\r
- \r
- matrix=composeTransform(mat,matrix)\r
- if result.end()<len(transf):\r
- return(parseTransform(transf[result.end():],matrix))\r
- else:\r
- return matrix\r
-\r
-def formatTransform(mat):\r
- 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]))\r
-\r
-def composeTransform(M1,M2):\r
- a11=M1[0][0]*M2[0][0]+M1[0][1]*M2[1][0]\r
- a12=M1[0][0]*M2[0][1]+M1[0][1]*M2[1][1]\r
- a21=M1[1][0]*M2[0][0]+M1[1][1]*M2[1][0]\r
- a22=M1[1][0]*M2[0][1]+M1[1][1]*M2[1][1]\r
-\r
- v1=M1[0][0]*M2[0][2]+M1[0][1]*M2[1][2]+M1[0][2]\r
- v2=M1[1][0]*M2[0][2]+M1[1][1]*M2[1][2]+M1[1][2]\r
- return [[a11,a12,v1],[a21,a22,v2]]\r
-\r
-def applyTransformToNode(mat,node):\r
- m=parseTransform(node.get("transform"))\r
- newtransf=formatTransform(composeTransform(mat,m))\r
- node.set("transform", newtransf)\r
-\r
-def applyTransformToPoint(mat,pt):\r
- x=mat[0][0]*pt[0]+mat[0][1]*pt[1]+mat[0][2]\r
- y=mat[1][0]*pt[0]+mat[1][1]*pt[1]+mat[1][2]\r
- pt[0]=x\r
- pt[1]=y\r
-\r
-def applyTransformToPath(mat,path):\r
- for comp in path:\r
- for ctl in comp:\r
- for pt in ctl:\r
- applyTransformToPoint(mat,pt)\r
-\r
-def fuseTransform(node):\r
- if node.get('d')==None:\r
- #FIX ME: how do you raise errors?\r
- raise AssertionError, 'can not fuse "transform" of elements that have no "d" attribute'\r
- t = node.get("transform")\r
- if t == None:\r
- return\r
- m = parseTransform(t)\r
- d = node.get('d')\r
- p = cubicsuperpath.parsePath(d)\r
- applyTransformToPath(m,p)\r
- node.set('d', cubicsuperpath.formatPath(p))\r
- del node.attrib["transform"]\r
-\r
-####################################################################\r
-##-- Some functions to compute a rough bbox of a given list of objects.\r
-##-- this should be shipped out in an separate file...\r
-\r
-def boxunion(b1,b2):\r
- if b1 is None:\r
- return b2\r
- elif b2 is None:\r
- return b1 \r
- else:\r
- return((min(b1[0],b2[0]),max(b1[1],b2[1]),min(b1[2],b2[2]),max(b1[3],b2[3])))\r
-\r
-def roughBBox(path):\r
- xmin,xMax,ymin,yMax=path[0][0][0][0],path[0][0][0][0],path[0][0][0][1],path[0][0][0][1]\r
- for pathcomp in path:\r
- for ctl in pathcomp:\r
- for pt in ctl:\r
- xmin=min(xmin,pt[0])\r
- xMax=max(xMax,pt[0])\r
- ymin=min(ymin,pt[1])\r
- yMax=max(yMax,pt[1])\r
- return xmin,xMax,ymin,yMax\r
-\r
-def computeBBox(aList,mat=[[1,0,0],[0,1,0]]):\r
- bbox=None\r
- for node in aList:\r
- m = parseTransform(node.get('transform'))\r
- m = composeTransform(mat,m)\r
- #TODO: text not supported!\r
- if node.get("d"):\r
- d = node.get('d')\r
- p = cubicsuperpath.parsePath(d)\r
- applyTransformToPath(m,p)\r
- bbox=boxunion(roughBBox(p),bbox)\r
-\r
- elif node.tag == inkex.addNS('rect','svg') or node.tag=='rect':\r
- w = float(node.get('width'))/2.\r
- h = float(node.get('height'))/2.\r
- x = float(node.get('x'))\r
- y = float(node.get('y'))\r
- C = [x + w , y + h ]\r
- applyTransformToPoint(mat,C)\r
- xmin = C[0] - abs(m[0][0]) * w - abs(m[0][1]) * h\r
- xmax = C[0] + abs(m[0][0]) * w + abs(m[0][1]) * h\r
- ymin = C[1] - abs(m[1][0]) * w - abs(m[1][1]) * h\r
- ymax = C[1] + abs(m[1][0]) * w + abs(m[1][1]) * h\r
- bbox = xmin,xmax,ymin,ymax\r
- \r
- elif node.tag == inkex.addNS('use','svg') or node.tag=='use':\r
- refid=node.get(inkex.addNS('href','xlink'))\r
- path = '//*[@id="%s"]' % refid[1:]\r
- refnode = node.xpath(path)\r
- bbox=boxunion(computeBBox(refnode,m),bbox)\r
- \r
- bbox=boxunion(computeBBox(node,m),bbox)\r
- return bbox\r
-\r
-\r
+#!/usr/bin/env python
+'''
+Copyright (C) 2006 Jean-Francois Barraud, barraud@math.univ-lille1.fr
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+barraud@math.univ-lille1.fr
+
+This code defines several functions to make handling of transform
+attribute easier.
+'''
+import inkex, cubicsuperpath, bezmisc, simplestyle
+import copy, math, re
+
+def parseTransform(transf,mat=[[1.0,0.0,0.0],[0.0,1.0,0.0]]):
+ if transf=="" or transf==None:
+ return(mat)
+ stransf = transf.strip()
+ result=re.match("(translate|scale|rotate|skewX|skewY|matrix)\s*\(([^)]*)\)\s*,?",stransf)
+#-- translate --
+ if result.group(1)=="translate":
+ args=result.group(2).replace(',',' ').split()
+ dx=float(args[0])
+ if len(args)==1:
+ dy=0.0
+ else:
+ dy=float(args[1])
+ matrix=[[1,0,dx],[0,1,dy]]
+#-- scale --
+ if result.group(1)=="scale":
+ args=result.group(2).replace(',',' ').split()
+ sx=float(args[0])
+ if len(args)==1:
+ sy=sx
+ else:
+ sy=float(args[1])
+ matrix=[[sx,0,0],[0,sy,0]]
+#-- rotate --
+ if result.group(1)=="rotate":
+ args=result.group(2).replace(',',' ').split()
+ a=float(args[0])*math.pi/180
+ if len(args)==1:
+ cx,cy=(0.0,0.0)
+ else:
+ cx,cy=map(float,args[1:])
+ matrix=[[math.cos(a),-math.sin(a),cx],[math.sin(a),math.cos(a),cy]]
+#-- skewX --
+ if result.group(1)=="skewX":
+ a=float(result.group(2))*math.pi/180
+ matrix=[[1,math.tan(a),0],[0,1,0]]
+#-- skewY --
+ if result.group(1)=="skewY":
+ a=float(result.group(2))*math.pi/180
+ matrix=[[1,0,0],[math.tan(a),1,0]]
+#-- matrix --
+ if result.group(1)=="matrix":
+ a11,a21,a12,a22,v1,v2=result.group(2).replace(',',' ').split()
+ matrix=[[float(a11),float(a12),float(v1)],[float(a21),float(a22),float(v2)]]
+
+ matrix=composeTransform(mat,matrix)
+ if result.end()<len(stransf):
+ return(parseTransform(stransf[result.end():],matrix))
+ else:
+ return matrix
+
+def formatTransform(mat):
+ 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]))
+
+def composeTransform(M1,M2):
+ a11=M1[0][0]*M2[0][0]+M1[0][1]*M2[1][0]
+ a12=M1[0][0]*M2[0][1]+M1[0][1]*M2[1][1]
+ a21=M1[1][0]*M2[0][0]+M1[1][1]*M2[1][0]
+ a22=M1[1][0]*M2[0][1]+M1[1][1]*M2[1][1]
+
+ v1=M1[0][0]*M2[0][2]+M1[0][1]*M2[1][2]+M1[0][2]
+ v2=M1[1][0]*M2[0][2]+M1[1][1]*M2[1][2]+M1[1][2]
+ return [[a11,a12,v1],[a21,a22,v2]]
+
+def applyTransformToNode(mat,node):
+ m=parseTransform(node.get("transform"))
+ newtransf=formatTransform(composeTransform(mat,m))
+ node.set("transform", newtransf)
+
+def applyTransformToPoint(mat,pt):
+ x=mat[0][0]*pt[0]+mat[0][1]*pt[1]+mat[0][2]
+ y=mat[1][0]*pt[0]+mat[1][1]*pt[1]+mat[1][2]
+ pt[0]=x
+ pt[1]=y
+
+def applyTransformToPath(mat,path):
+ for comp in path:
+ for ctl in comp:
+ for pt in ctl:
+ applyTransformToPoint(mat,pt)
+
+def fuseTransform(node):
+ if node.get('d')==None:
+ #FIX ME: how do you raise errors?
+ raise AssertionError, 'can not fuse "transform" of elements that have no "d" attribute'
+ t = node.get("transform")
+ if t == None:
+ return
+ m = parseTransform(t)
+ d = node.get('d')
+ p = cubicsuperpath.parsePath(d)
+ applyTransformToPath(m,p)
+ node.set('d', cubicsuperpath.formatPath(p))
+ del node.attrib["transform"]
+
+####################################################################
+##-- Some functions to compute a rough bbox of a given list of objects.
+##-- this should be shipped out in an separate file...
+
+def boxunion(b1,b2):
+ if b1 is None:
+ return b2
+ elif b2 is None:
+ return b1
+ else:
+ return((min(b1[0],b2[0]),max(b1[1],b2[1]),min(b1[2],b2[2]),max(b1[3],b2[3])))
+
+def roughBBox(path):
+ xmin,xMax,ymin,yMax = path[0][0][0][0],path[0][0][0][0],path[0][0][0][1],path[0][0][0][1]
+ for pathcomp in path:
+ for ctl in pathcomp:
+ for pt in ctl:
+ xmin = min(xmin,pt[0])
+ xMax = max(xMax,pt[0])
+ ymin = min(ymin,pt[1])
+ yMax = max(yMax,pt[1])
+ return xmin,xMax,ymin,yMax
+
+def computeBBox(aList,mat=[[1,0,0],[0,1,0]]):
+ bbox=None
+ for node in aList:
+ m = parseTransform(node.get('transform'))
+ m = composeTransform(mat,m)
+ #TODO: text not supported!
+ if node.get("d"):
+ d = node.get('d')
+ p = cubicsuperpath.parsePath(d)
+ applyTransformToPath(m,p)
+ bbox=boxunion(roughBBox(p),bbox)
+
+ elif node.tag == inkex.addNS('rect','svg') or node.tag=='rect':
+ w = float(node.get('width'))/2.
+ h = float(node.get('height'))/2.
+ x = float(node.get('x'))
+ y = float(node.get('y'))
+ C = [x + w , y + h ]
+ applyTransformToPoint(mat,C)
+ xmin = C[0] - abs(m[0][0]) * w - abs(m[0][1]) * h
+ xmax = C[0] + abs(m[0][0]) * w + abs(m[0][1]) * h
+ ymin = C[1] - abs(m[1][0]) * w - abs(m[1][1]) * h
+ ymax = C[1] + abs(m[1][0]) * w + abs(m[1][1]) * h
+ bbox = xmin,xmax,ymin,ymax
+
+ elif node.tag == inkex.addNS('use','svg') or node.tag=='use':
+ refid=node.get(inkex.addNS('href','xlink'))
+ path = '//*[@id="%s"]' % refid[1:]
+ refnode = node.xpath(path)
+ bbox=boxunion(computeBBox(refnode,m),bbox)
+
+ bbox=boxunion(computeBBox(node,m),bbox)
+ return bbox
+
+
+# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99