home *** CD-ROM | disk | FTP | other *** search
/ Chip 2011 November / CHIP_2011_11.iso / Programy / Narzedzia / Inkscape / Inkscape-0.48.2-1-win32.exe / share / extensions / simpletransform.py < prev    next >
Text File  |  2011-07-08  |  7KB  |  195 lines

  1. #!/usr/bin/env python
  2. '''
  3. Copyright (C) 2006 Jean-Francois Barraud, barraud@math.univ-lille1.fr
  4.  
  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.
  9.  
  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.
  14.  
  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
  19.  
  20. This code defines several functions to make handling of transform
  21. attribute easier.
  22. '''
  23. import inkex, cubicsuperpath, bezmisc, simplestyle
  24. import copy, math, re
  25.  
  26. def parseTransform(transf,mat=[[1.0, 0.0, 0.0], [0.0, 1.0, 0.0]]):
  27.     if transf=="" or transf==None:
  28.         return(mat)
  29.     stransf = transf.strip()
  30.     result=re.match("(translate|scale|rotate|skewX|skewY|matrix)\s*\(([^)]*)\)\s*,?",stransf)
  31. #-- translate --
  32.     if result.group(1)=="translate":
  33.         args=result.group(2).replace(',',' ').split()
  34.         dx=float(args[0])
  35.         if len(args)==1:
  36.             dy=0.0
  37.         else:
  38.             dy=float(args[1])
  39.         matrix=[[1,0,dx],[0,1,dy]]
  40. #-- scale --
  41.     if result.group(1)=="scale":
  42.         args=result.group(2).replace(',',' ').split()
  43.         sx=float(args[0])
  44.         if len(args)==1:
  45.             sy=sx
  46.         else:
  47.             sy=float(args[1])
  48.         matrix=[[sx,0,0],[0,sy,0]]
  49. #-- rotate --
  50.     if result.group(1)=="rotate":
  51.         args=result.group(2).replace(',',' ').split()
  52.         a=float(args[0])*math.pi/180
  53.         if len(args)==1:
  54.             cx,cy=(0.0,0.0)
  55.         else:
  56.             cx,cy=map(float,args[1:])
  57.         matrix=[[math.cos(a),-math.sin(a),cx],[math.sin(a),math.cos(a),cy]]
  58.         matrix=composeTransform(matrix,[[1,0,-cx],[0,1,-cy]])
  59. #-- skewX --
  60.     if result.group(1)=="skewX":
  61.         a=float(result.group(2))*math.pi/180
  62.         matrix=[[1,math.tan(a),0],[0,1,0]]
  63. #-- skewY --
  64.     if result.group(1)=="skewY":
  65.         a=float(result.group(2))*math.pi/180
  66.         matrix=[[1,0,0],[math.tan(a),1,0]]
  67. #-- matrix --
  68.     if result.group(1)=="matrix":
  69.         a11,a21,a12,a22,v1,v2=result.group(2).replace(',',' ').split()
  70.         matrix=[[float(a11),float(a12),float(v1)], [float(a21),float(a22),float(v2)]]
  71.  
  72.     matrix=composeTransform(mat,matrix)
  73.     if result.end() < len(stransf):
  74.         return(parseTransform(stransf[result.end():], matrix))
  75.     else:
  76.         return matrix
  77.  
  78. def formatTransform(mat):
  79.     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.  
  81. def composeTransform(M1,M2):
  82.     a11 = M1[0][0]*M2[0][0] + M1[0][1]*M2[1][0]
  83.     a12 = M1[0][0]*M2[0][1] + M1[0][1]*M2[1][1]
  84.     a21 = M1[1][0]*M2[0][0] + M1[1][1]*M2[1][0]
  85.     a22 = M1[1][0]*M2[0][1] + M1[1][1]*M2[1][1]
  86.  
  87.     v1 = M1[0][0]*M2[0][2] + M1[0][1]*M2[1][2] + M1[0][2]
  88.     v2 = M1[1][0]*M2[0][2] + M1[1][1]*M2[1][2] + M1[1][2]
  89.     return [[a11,a12,v1],[a21,a22,v2]]
  90.  
  91. def applyTransformToNode(mat,node):
  92.     m=parseTransform(node.get("transform"))
  93.     newtransf=formatTransform(composeTransform(mat,m))
  94.     node.set("transform", newtransf)
  95.  
  96. def applyTransformToPoint(mat,pt):
  97.     x = mat[0][0]*pt[0] + mat[0][1]*pt[1] + mat[0][2]
  98.     y = mat[1][0]*pt[0] + mat[1][1]*pt[1] + mat[1][2]
  99.     pt[0]=x
  100.     pt[1]=y
  101.  
  102. def applyTransformToPath(mat,path):
  103.     for comp in path:
  104.         for ctl in comp:
  105.             for pt in ctl:
  106.                 applyTransformToPoint(mat,pt)
  107.  
  108. def fuseTransform(node):
  109.     if node.get('d')==None:
  110.         #FIXME: how do you raise errors?
  111.         raise AssertionError, 'can not fuse "transform" of elements that have no "d" attribute'
  112.     t = node.get("transform")
  113.     if t == None:
  114.         return
  115.     m = parseTransform(t)
  116.     d = node.get('d')
  117.     p = cubicsuperpath.parsePath(d)
  118.     applyTransformToPath(m,p)
  119.     node.set('d', cubicsuperpath.formatPath(p))
  120.     del node.attrib["transform"]
  121.  
  122. ####################################################################
  123. ##-- Some functions to compute a rough bbox of a given list of objects.
  124. ##-- this should be shipped out in an separate file...
  125.  
  126. def boxunion(b1,b2):
  127.     if b1 is None:
  128.         return b2
  129.     elif b2 is None:
  130.         return b1    
  131.     else:
  132.         return((min(b1[0],b2[0]), max(b1[1],b2[1]), min(b1[2],b2[2]), max(b1[3],b2[3])))
  133.  
  134. def roughBBox(path):
  135.     xmin,xMax,ymin,yMax = path[0][0][0][0],path[0][0][0][0],path[0][0][0][1],path[0][0][0][1]
  136.     for pathcomp in path:
  137.         for ctl in pathcomp:
  138.             for pt in ctl:
  139.                 xmin = min(xmin,pt[0])
  140.                 xMax = max(xMax,pt[0])
  141.                 ymin = min(ymin,pt[1])
  142.                 yMax = max(yMax,pt[1])
  143.     return xmin,xMax,ymin,yMax
  144.  
  145. def computeBBox(aList,mat=[[1,0,0],[0,1,0]]):
  146.     bbox=None
  147.     for node in aList:
  148.         m = parseTransform(node.get('transform'))
  149.         m = composeTransform(mat,m)
  150.         #TODO: text not supported!
  151.         d = None
  152.         if node.get("d"):
  153.             d = node.get('d')
  154.         elif node.get('points'):
  155.             d = 'M' + node.get('points')
  156.         elif node.tag in [ inkex.addNS('rect','svg'), 'rect' ]:
  157.             d = 'M' + node.get('x', '0') + ',' + node.get('y', '0') + \
  158.                 'h' + node.get('width') + 'v' + node.get('height') + \
  159.                 'h-' + node.get('width')
  160.         elif node.tag in [ inkex.addNS('line','svg'), 'line' ]:
  161.             d = 'M' + node.get('x1') + ',' + node.get('y1') + \
  162.                 ' ' + node.get('x2') + ',' + node.get('y2')
  163.         elif node.tag in [ inkex.addNS('circle','svg'), 'circle', \
  164.                             inkex.addNS('ellipse','svg'), 'ellipse' ]:
  165.             rx = node.get('r')
  166.             if rx is not None:
  167.                 ry = rx
  168.             else:
  169.                 rx = node.get('rx')
  170.                 ry = node.get('ry')
  171.             cx = float(node.get('cx', '0'))
  172.             cy = float(node.get('cy', '0'))
  173.             x1 = cx - float(rx)
  174.             x2 = cx + float(rx)
  175.             d = 'M %f %f ' % (x1, cy) + \
  176.                 'A' + rx + ',' + ry + ' 0 1 0 %f,%f' % (x2, cy) + \
  177.                 'A' + rx + ',' + ry + ' 0 1 0 %f,%f' % (x1, cy)
  178.  
  179.         if d is not None:
  180.             p = cubicsuperpath.parsePath(d)
  181.             applyTransformToPath(m,p)
  182.             bbox=boxunion(roughBBox(p),bbox)
  183.  
  184.         elif node.tag == inkex.addNS('use','svg') or node.tag=='use':
  185.             refid=node.get(inkex.addNS('href','xlink'))
  186.             path = '//*[@id="%s"]' % refid[1:]
  187.             refnode = node.xpath(path)
  188.             bbox=boxunion(computeBBox(refnode,m),bbox)
  189.             
  190.         bbox=boxunion(computeBBox(node,m),bbox)
  191.     return bbox
  192.  
  193.  
  194. # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99
  195.