diff options
| author | popolon.org <popolon@popolon.org> | 2008-01-29 00:23:07 +0000 |
|---|---|---|
| committer | popolon2 <popolon2@users.sourceforge.net> | 2008-01-29 00:23:07 +0000 |
| commit | f2ce548574053205c1e3d950e2e849078272e17f (patch) | |
| tree | d5e74f3cd8a9f9431f8dc929da3d00a43b5ea306 | |
| parent | noop: Address some cast-string-to-mutable-chars warnings. (diff) | |
| download | inkscape-f2ce548574053205c1e3d950e2e849078272e17f.tar.gz inkscape-f2ce548574053205c1e3d950e2e849078272e17f.zip | |
Update JF Barraud scripts to work with actual SVN see https://bugs.launchpad.net/inkscape/+bug/182832 (interpolate is not modified, and new scatter scripts not added)
(bzr r4613)
| -rw-r--r-- | share/extensions/pathalongpath.inx | 46 | ||||
| -rw-r--r-- | share/extensions/pathalongpath.py | 19 | ||||
| -rw-r--r-- | share/extensions/pathmodifier.py | 286 | ||||
| -rw-r--r-- | share/extensions/rubberstretch.py | 8 | ||||
| -rw-r--r-- | share/extensions/simpletransform.py | 164 |
5 files changed, 308 insertions, 215 deletions
diff --git a/share/extensions/pathalongpath.inx b/share/extensions/pathalongpath.inx index ce489a9e2..3011f015a 100644 --- a/share/extensions/pathalongpath.inx +++ b/share/extensions/pathalongpath.inx @@ -1,38 +1,38 @@ <inkscape-extension>
<_name>Pattern along Path</_name>
<id>math.univ-lille1.barraud.pathdeform</id>
- <dependency type="executable" location="extensions">pathmodifier.py</dependency>
- <dependency type="executable" location="extensions">pathalongpath.py</dependency>
- <dependency type="executable" location="extensions">inkex.py</dependency>
- <param name="title" type="description">This effect bends a pattern object along an arbitrary "skeleton" path. The pattern can be a path or a group of paths. First, select the pattern object; then add to selection the skeleton path; then call this effect.</param>
+<dependency type="executable" location="extensions">pathmodifier.py</dependency>
+<dependency type="executable" location="extensions">pathalongpath.py</dependency>
+<dependency type="executable" location="extensions">inkex.py</dependency>
+<param name="title" type="description">This effect bends a pattern object along arbitrary "skeleton" paths. The pattern is the top most object in the selection. (groups of paths/shapes/clones... allowed)</param>
- <param name="copymode" type="enum" _gui-text="Copies of the pattern:">
- <item value="Single">Single</item>
- <item value="Single, stretched">Single, stretched</item>
- <item value="Repeated">Repeated</item>
- <item value="Repeated, stretched">Repeated, stretched</item>
- </param>
+<param name="copymode" type="enum" _gui-text="Copies of the pattern:">
+ <item value="Single">Single</item>
+ <item value="Single, stretched">Single, stretched</item>
+ <item value="Repeated">Repeated</item>
+ <item value="Repeated, stretched">Repeated, stretched</item>
+</param>
- <param name="kind" type="enum" _gui-text="Deformation type:">
- <item value="Snake">Snake</item>
- <item value="Ribbon">Ribbon</item>
- </param>
+<param name="kind" type="enum" _gui-text="Deformation type:">
+ <item value="Snake">Snake</item>
+ <item value="Ribbon">Ribbon</item>
+</param>
- <param name="space" type="float" _gui-text="Space between copies:" min="-10000.0" max="10000.0" >0.0</param>
+<param name="space" type="float" _gui-text="Space between copies:" min="-10000.0" max="10000.0" >0.0</param>
- <param name="noffset" type="float" _gui-text="Normal offset" min="-10000.0" max="10000.0">0.0</param>
- <param name="toffset" type="float" _gui-text="Tangential offset" min="-10000.0" max="10000.0" >0.0</param>
+<param name="noffset" type="float" _gui-text="Normal offset" min="-10000.0" max="10000.0">0.0</param>
+<param name="toffset" type="float" _gui-text="Tangential offset" min="-10000.0" max="10000.0" >0.0</param>
- <param name="vertical" type="boolean" _gui-text="Pattern is vertical">false</param>
- <param name="duplicate" type="boolean" _gui-text="Duplicate the pattern before deformation">true</param>
+<param name="vertical" type="boolean" _gui-text="Pattern is vertical">false</param>
+<param name="duplicate" type="boolean" _gui-text="Duplicate the pattern before deformation">true</param>
<effect>
- <effects-menu>
- <submenu _name="Generate from Path"/>
- </effects-menu>
+<effects-menu>
+<submenu _name="Generate from Path"/>
+</effects-menu>
</effect>
<script>
<command reldir="extensions" interpreter="python">pathalongpath.py</command>
</script>
</inkscape-extension>
-
+
diff --git a/share/extensions/pathalongpath.py b/share/extensions/pathalongpath.py index e49aadeb4..a8285b9f8 100644 --- a/share/extensions/pathalongpath.py +++ b/share/extensions/pathalongpath.py @@ -32,7 +32,7 @@ they move and rotate, deforming the pattern. '''
import inkex, cubicsuperpath, bezmisc
-import pathmodifier
+import pathmodifier,simpletransform
import copy, math, re, random
@@ -118,9 +118,16 @@ class PathAlongPath(pathmodifier.Diffeo): help="duplicate pattern before deformation")
def prepareSelectionList(self):
- ##first selected->pattern, all but first selected-> skeletons
- id = self.options.ids[-1]
+
+ idList=self.options.ids
+ idList=pathmodifier.zSort(self.document.getroot(),idList)
+ id = idList[-1]
self.patterns={id:self.selected[id]}
+
+## ##first selected->pattern, all but first selected-> skeletons
+## id = self.options.ids[-1]
+## self.patterns={id:self.selected[id]}
+
if self.options.duplicate:
self.patterns=self.duplicateNodes(self.patterns)
self.expandGroupsUnlinkClones(self.patterns, True, True)
@@ -203,7 +210,8 @@ class PathAlongPath(pathmodifier.Diffeo): self.options.repeat =True
self.options.stretch=True
- bbox=self.computeBBox(self.patterns)
+ bbox=simpletransform.computeBBox(self.patterns.values())
+
if self.options.vertical:
#flipxy(bbox)...
bbox=(-bbox[3],-bbox[2],-bbox[1],-bbox[0])
@@ -233,12 +241,13 @@ class PathAlongPath(pathmodifier.Diffeo): xoffset=self.skelcomp[0][0]-bbox[0]+self.options.toffset
yoffset=self.skelcomp[0][1]-(bbox[2]+bbox[3])/2-self.options.noffset
+
if self.options.repeat:
NbCopies=max(1,int(round((length+self.options.space)/dx)))
width=dx*NbCopies
if not self.skelcompIsClosed:
width-=self.options.space
- bbox=bbox[0],bbox[0]+width,bbox[2],bbox[3]
+ bbox=bbox[0],bbox[0]+width, bbox[2],bbox[3]
new=[]
for sub in p:
for i in range(0,NbCopies,1):
diff --git a/share/extensions/pathmodifier.py b/share/extensions/pathmodifier.py index baa31fca2..a7e312ae0 100644 --- a/share/extensions/pathmodifier.py +++ b/share/extensions/pathmodifier.py @@ -16,117 +16,35 @@ 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 a basic class (PathModifier) of effects whose purpose is
+to somehow deform given objects: one common tasks for all such effect is to
+convert shapes, groups, clones to paths. The class has several functions to
+make this (more or less!) easy.
+As an exemple, a second class (Diffeo) is derived from it,
+to implement deformations of the form X=f(x,y), Y=g(x,y)...
+
+TODO: Several handy functions are defined, that might in fact be of general
+interest and that should be shipped out in separate files...
'''
import inkex, cubicsuperpath, bezmisc, simplestyle
+from simpletransform import *
import copy, math, re, random
-def parseTransform(transf,mat=[[1.0,0.0,0.0],[0.0,1.0,0.0]]):
- if transf=="":
- return(mat)
- result=re.match("(translate|scale|rotate|skewX|skewY|matrix)\(([^)]*)\)",transf)
-#-- translate --
- if result.group(1)=="translate":
- args=result.group(2).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.groups(1)=="scale":
- args=result.group(2).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.groups(1)=="rotate":
- args=result.group(2).split(",")
- a=float(args[0])*math.pi/180
- if len(args)==1:
- cx,cy=(0.0,0.0)
- else:
- cx,cy=args[1:]
- matrix=[[math.cos(a),-math.sin(a),cx],[math.sin(a),math.cos(a),cy]]
-#-- skewX --
- if result.groups(1)=="skewX":
- a=float(result.group(2))*math.pi/180
- matrix=[[1,math.tan(a),0],[0,1,0]]
-#-- skewX --
- if result.groups(1)=="skewX":
- 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).split(",")
- matrix=[[float(a11),float(a12),float(v1)],[float(a21),float(a22),float(v2)]]
-
- matrix=composeTransform(mat,matrix)
- if result.end()<len(transf):
- return(parseTransform(transf[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 fuseTransform(node):
- t = node.get("transform")
- if t == None:
- return
- m=parseTransform(t)
- d = node.get('d')
- p=cubicsuperpath.parsePath(d)
- for comp in p:
- for ctl in comp:
- for pt in ctl:
- applyTransformToPoint(m,pt)
- node.set('d', cubicsuperpath.formatPath(p))
- del node.attrib["transform"]
-
-
-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
+####################################################################
+##-- zOrder computation...
+##-- this should be shipped out in a separate file. inkex.py?
+
+def zSort(inNode,idList):
+ sortedList=[]
+ theid = inNode.get("id")
+ if theid in idList:
+ sortedList.append(theid)
+ for child in inNode:
+ if len(sortedList)==len(idList):
+ break
+ sortedList+=zSort(child,idList)
+ return sortedList
class PathModifier(inkex.Effect):
@@ -136,14 +54,6 @@ class PathModifier(inkex.Effect): ##################################
#-- Selectionlists manipulation --
##################################
- def computeBBox(self, aList):
- bbox=None
- for id, node in aList.iteritems():
- if node.tag == inkex.addNS('path','svg') or node.tag == 'path':
- d = node.get('d')
- p = cubicsuperpath.parsePath(d)
- bbox=boxunion(roughBBox(p),bbox)
- return bbox
def duplicateNodes(self, aList):
clones={}
@@ -171,7 +81,7 @@ class PathModifier(inkex.Effect): if transferTransform:
applyTransformToNode(mat,child)
aList.update(self.expandGroups({child.get('id'):child}))
- if transferTransform:
+ if transferTransform and node.get("transform"):
del node.attrib["transform"]
del aList[id]
return(aList)
@@ -183,25 +93,17 @@ class PathModifier(inkex.Effect): self.expandGroups(aList,transferTransform)
self.expandGroupsUnlinkClones(aList,transferTransform,doReplace)
#Hum... not very efficient if there are many clones of groups...
+
elif node.tag == inkex.addNS('use','svg') or node.tag=='use':
- refid=node.get(inkex.addNS('href','xlink'))
- path = '//*[@id="%s"]' % refid[1:]
- refnode = self.document.getroot().xpath(path,inkex.NSS)
- newnode=copy.deepcopy(refnode)
- self.recursNewIds(newnode)
-
- s = node.get('style')
- if s:
- style=simplestyle.parseStyle(s)
- refstyle=simplestyle.parseStyle(refnode.get('style'))
- style.update(refstyle)
- newnode.set('style',simplestyle.formatStyle(style))
- applyTransformToNode(parseTransform(node.get('transform')),newnode)
- if doReplace:
- parent=node.getparent()
- parent.insert(node.index,newnode)
- parent.remove(node)
- del aList[id]
+ refnode=self.refNode(node)
+ newnode=self.unlinkClone(node,doReplace)
+ del aList[id]
+
+ style = simplestyle.parseStyle(node.get('style') or "")
+ refstyle=simplestyle.parseStyle(refnode.get('style') or "")
+ style.update(refstyle)
+ newnode.set('style',simplestyle.formatStyle(style))
+
newid=newnode.get('id')
aList.update(self.expandGroupsUnlinkClones({newid:newnode},transferTransform,doReplace))
return aList
@@ -212,38 +114,31 @@ class PathModifier(inkex.Effect): for child in node:
self.recursNewIds(child)
+ def refNode(self,node):
+ if node.get(inkex.addNS('href','xlink')):
+ refid=node.get(inkex.addNS('href','xlink'))
+ path = '//*[@id="%s"]' % refid[1:]
+ newNode = self.document.getroot().xpath(path,inkex.NSS)[0]
+ return newNode
+ else:
+ raise AssertionError, "Trying to follow empty xlink.href attribute."
+
+ def unlinkClone(self,node,doReplace):
+ if node.tag == inkex.addNS('use','svg') or node.tag=='use':
+ newNode = copy.deepcopy(self.refNode(node))
+ self.recursNewIds(newNode)
+ applyTransformToNode(parseTransform(node.get('transform')),newNode)
+
+ if doReplace:
+ parent=node.getparent()
+ parent.insert(parent.index(node),newNode)
+ parent.remove(node)
+
+ return newNode
+ else:
+ raise AssertionError, "Only clones can be unlinked..."
+
-
-# Had not been rewritten for ElementTree
-# def makeClonesReal(self,aList,doReplace=True,recursivelytransferTransform=True):
-# for id in aList.keys():
-# node=aList[id]
-# if node.tagName == 'g':
-# childs={}
-# for child in node.childNodes:
-# if child.nodeType==child.ELEMENT_NODE:
-# childid=child.getAttributeNS(None,'id')
-# del aList[childid]
-# aList.update(self.makeClonesReal({childid:child},doReplace))
-# elif node.tagName == 'use':
-# refid=node.getAttributeNS(inkex.NSS[u'xlink'],'href')
-# path = '//*[@id="%s"]' % refid[1:]
-# refnode = xml.xpath.Evaluate(path,document)[0]
-# clone=refnode.cloneNode(True)
-# cloneid=self.uniqueId(clone.tagName)
-# clone.setAttributeNS(None,'id', cloneid)
-# style=simplestyle.parseStyle(node.getAttributeNS(None,u'style'))
-# refstyle=simplestyle.parseStyle(refnode.getAttributeNS(None,u'style'))
-# style.update(refstyle)
-# clone.setAttributeNS(None,'style',simplestyle.formatStyle(style))
-# applyTransformToNode(parseTransform(node.getAttributeNS(None,'transform')),clone)
-# if doReplace:
-# parent=node.parentNode
-# parent.insertBefore(clone,node)
-# parent.removeChild(node)
-# del aList[id]
-# aList.update(self.expandGroupsUnlinkClones({cloneid:clone}))
-# return aList
################################
#-- Object conversion ----------
@@ -282,27 +177,52 @@ class PathModifier(inkex.Effect): fuseTransform(newnode)
if doReplace:
parent=node.getparent()
- parent.insert(node.index,newnode)
+ parent.insert(parent.index(node),newnode)
parent.remove(node)
return newnode
+ def groupToPath(self,node,doReplace=True):
+ if node.tag == inkex.addNS('g','svg'):
+ newNode = inkex.etree.SubElement(self.current_layer,inkex.addNS('path','svg'))
+
+ newstyle = simplestyle.parseStyle(node.get('style') or "")
+ newp = []
+ for child in node:
+ childstyle = simplestyle.parseStyle(child.get('style') or "")
+ childstyle.update(newstyle)
+ newstyle.update(childstyle)
+ childAsPath = self.objectToPath(child,False)
+ newp += cubicsuperpath.parsePath(childAsPath.get('d'))
+ newNode.set('d',cubicsuperpath.formatPath(newp))
+ newNode.set('style',simplestyle.formatStyle(newstyle))
+
+ self.current_layer.remove(newNode)
+ if doReplace:
+ parent=node.getparent()
+ parent.insert(parent.index(node),newNode)
+ parent.remove(node)
+
+ return newNode
+ else:
+ raise AssertionError
+
def objectToPath(self,node,doReplace=True):
#--TODO: support other object types!!!!
#--TODO: make sure cubicsuperpath supports A and Q commands...
if node.tag == inkex.addNS('rect','svg'):
return(self.rectToPath(node,doReplace))
+ if node.tag == inkex.addNS('g','svg'):
+ return(self.groupToPath(node,doReplace))
elif node.tag == inkex.addNS('path','svg') or node.tag == 'path':
- attributes = node.keys()
- for attName in attributes:
- uri = None
- if attName[0] == '{':
- uri,attName = attName.split('}')
- uri = uri[1:]
- if uri in [inkex.NSS[u'sodipodi'],inkex.NSS[u'inkscape']]:
- #if attName not in ["d","id","style","transform"]:
- del node.attrib[inkex.addNS(attName,uri)]
+ #remove inkscape attributes, otherwise any modif of 'd' will be discarded!
+ for attName in node.attrib.keys():
+ if ("sodipodi" in attName) or ("inkscape" in attName):
+ del node.attrib[attName]
fuseTransform(node)
return node
+ elif node.tag == inkex.addNS('use','svg') or node.tag == 'use':
+ newNode = self.unlinkClone(node,doReplace)
+ return self.objectToPath(newNode,doReplace)
else:
inkex.debug("Please first convert objects to paths!...(got '%s')"%node.tag)
return None
@@ -310,7 +230,7 @@ class PathModifier(inkex.Effect): def objectsToPaths(self,aList,doReplace=True):
newSelection={}
for id,node in aList.items():
- newnode=self.objectToPath(node,self.document)
+ newnode=self.objectToPath(node,doReplace)
del aList[id]
aList[newnode.get('id')]=newnode
@@ -322,17 +242,17 @@ class PathModifier(inkex.Effect): #-- overwrite this method in subclasses...
def effect(self):
#self.duplicateNodes(self.selected)
- self.expandGroupsUnlinkClones(self.selected, True)
+ #self.expandGroupsUnlinkClones(self.selected, True)
self.objectsToPaths(self.selected, True)
- self.bbox=self.computeBBox(self.selected)
+ self.bbox=computeBBox(self.selected.values())
for id, node in self.selected.iteritems():
if node.tag == inkex.addNS('path','svg'):
d = node.get('d')
p = cubicsuperpath.parsePath(d)
- #do what ever you want with p!
+ #do what ever you want with p!
- node.set('d',cubicsuperpath.formatPath(p))
+ node.set('d',cubicsuperpath.formatPath(p))
class Diffeo(PathModifier):
@@ -369,7 +289,7 @@ class Diffeo(PathModifier): self.expandGroupsUnlinkClones(self.selected, True)
self.expandGroups(self.selected, True)
self.objectsToPaths(self.selected, True)
- self.bbox=self.computeBBox(self.selected)
+ self.bbox=computeBBox(self.selected.values())
for id, node in self.selected.iteritems():
if node.tag == inkex.addNS('path','svg') or node.tag=='path':
d = node.get('d')
@@ -383,5 +303,5 @@ class Diffeo(PathModifier): #e = Diffeo()
#e.affect()
- - +
+
diff --git a/share/extensions/rubberstretch.py b/share/extensions/rubberstretch.py index 1ea533cf0..60b1738c6 100644 --- a/share/extensions/rubberstretch.py +++ b/share/extensions/rubberstretch.py @@ -20,7 +20,7 @@ barraud@math.univ-lille1.fr '''
import inkex, cubicsuperpath, bezmisc, pathmodifier
-import copy, math, re, random, xml.xpath
+import copy, math, re
class RubberStretch(pathmodifier.Diffeo):
def __init__(self):
@@ -45,7 +45,7 @@ class RubberStretch(pathmodifier.Diffeo): w,h=(self.bbox[1]-self.bbox[0])/2,(self.bbox[3]-self.bbox[2])/2
x,y=(bpt[0]-x0),(bpt[1]-y0)
- sx=(1+b*(x/w+1)*(x/w-1))*2**(-a)
+ sx=(1+b*(x/w+1)*(x/w-1))*2**(-a)
sy=(1+b*(y/h+1)*(y/h-1))*2**(-a)
bpt[0]=x0+x*sy
bpt[1]=y0+y/sx
@@ -75,5 +75,5 @@ class RubberStretch(pathmodifier.Diffeo): e = RubberStretch()
e.affect()
- - +
+
diff --git a/share/extensions/simpletransform.py b/share/extensions/simpletransform.py new file mode 100644 index 000000000..983874f7c --- /dev/null +++ b/share/extensions/simpletransform.py @@ -0,0 +1,164 @@ +#!/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)
+ result=re.match("(translate|scale|rotate|skewX|skewY|matrix)\(([^)]*)\)",transf)
+#-- translate --
+ if result.group(1)=="translate":
+ args=result.group(2).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.groups(1)=="scale":
+ args=result.group(2).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.groups(1)=="rotate":
+ args=result.group(2).split(",")
+ a=float(args[0])*math.pi/180
+ if len(args)==1:
+ cx,cy=(0.0,0.0)
+ else:
+ cx,cy=args[1:]
+ matrix=[[math.cos(a),-math.sin(a),cx],[math.sin(a),math.cos(a),cy]]
+#-- skewX --
+ if result.groups(1)=="skewX":
+ a=float(result.group(2))*math.pi/180
+ matrix=[[1,math.tan(a),0],[0,1,0]]
+#-- skewX --
+ if result.groups(1)=="skewX":
+ 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).split(",")
+ matrix=[[float(a11),float(a12),float(v1)],[float(a21),float(a22),float(v2)]]
+
+ matrix=composeTransform(mat,matrix)
+ if result.end()<len(transf):
+ return(parseTransform(transf[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)
+
+ if node.tag == inkex.addNS('use','svg') or node.tag=='use':
+ refid=node.get(inkex.addNS('href','xlink'))
+ path = '//*[@id="%s"]' % refid[1:]
+ refnode = node.getroottree().xpath(path,inkex.NSS)
+ bbox=boxunion(computeBBox(refnode,m),bbox)
+
+ bbox=boxunion(computeBBox(node,m),bbox)
+ return bbox
+
+
|
