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 / simplepath.py < prev    next >
Text File  |  2011-07-08  |  7KB  |  213 lines

  1. #!/usr/bin/env python
  2. """
  3. simplepath.py
  4. functions for digesting paths into a simple list structure
  5.  
  6. Copyright (C) 2005 Aaron Spike, aaron@ekips.org
  7.  
  8. This program is free software; you can redistribute it and/or modify
  9. it under the terms of the GNU General Public License as published by
  10. the Free Software Foundation; either version 2 of the License, or
  11. (at your option) any later version.
  12.  
  13. This program is distributed in the hope that it will be useful,
  14. but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16. GNU General Public License for more details.
  17.  
  18. You should have received a copy of the GNU General Public License
  19. along with this program; if not, write to the Free Software
  20. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  21.  
  22. """
  23. import re, math
  24.  
  25. def lexPath(d):
  26.     """
  27.     returns and iterator that breaks path data 
  28.     identifies command and parameter tokens
  29.     """
  30.     offset = 0
  31.     length = len(d)
  32.     delim = re.compile(r'[ \t\r\n,]+')
  33.     command = re.compile(r'[MLHVCSQTAZmlhvcsqtaz]')
  34.     parameter = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)')
  35.     while 1:
  36.         m = delim.match(d, offset)
  37.         if m:
  38.             offset = m.end()
  39.         if offset >= length:
  40.             break
  41.         m = command.match(d, offset)
  42.         if m:
  43.             yield [d[offset:m.end()], True]
  44.             offset = m.end()
  45.             continue
  46.         m = parameter.match(d, offset)
  47.         if m:
  48.             yield [d[offset:m.end()], False]
  49.             offset = m.end()
  50.             continue
  51.         #TODO: create new exception
  52.         raise Exception, 'Invalid path data!'
  53. '''
  54. pathdefs = {commandfamily:
  55.     [
  56.     implicitnext,
  57.     #params,
  58.     [casts,cast,cast],
  59.     [coord type,x,y,0]
  60.     ]}
  61. '''
  62. pathdefs = {
  63.     'M':['L', 2, [float, float], ['x','y']], 
  64.     'L':['L', 2, [float, float], ['x','y']], 
  65.     'H':['H', 1, [float], ['x']], 
  66.     'V':['V', 1, [float], ['y']], 
  67.     'C':['C', 6, [float, float, float, float, float, float], ['x','y','x','y','x','y']], 
  68.     'S':['S', 4, [float, float, float, float], ['x','y','x','y']], 
  69.     'Q':['Q', 4, [float, float, float, float], ['x','y','x','y']], 
  70.     'T':['T', 2, [float, float], ['x','y']], 
  71.     'A':['A', 7, [float, float, float, int, int, float, float], ['r','r','a',0,'s','x','y']], 
  72.     'Z':['L', 0, [], []]
  73.     }
  74. def parsePath(d):
  75.     """
  76.     Parse SVG path and return an array of segments.
  77.     Removes all shorthand notation.
  78.     Converts coordinates to absolute.
  79.     """
  80.     retval = []
  81.     lexer = lexPath(d)
  82.  
  83.     pen = (0.0,0.0)
  84.     subPathStart = pen
  85.     lastControl = pen
  86.     lastCommand = ''
  87.     
  88.     while 1:
  89.         try:
  90.             token, isCommand = lexer.next()
  91.         except StopIteration:
  92.             break
  93.         params = []
  94.         needParam = True
  95.         if isCommand:
  96.             if not lastCommand and token.upper() != 'M':
  97.                 raise Exception, 'Invalid path, must begin with moveto.'    
  98.             else:                
  99.                 command = token
  100.         else:
  101.             #command was omited
  102.             #use last command's implicit next command
  103.             needParam = False
  104.             if lastCommand:
  105.                 if lastCommand.isupper():
  106.                     command = pathdefs[lastCommand][0]
  107.                 else:
  108.                     command = pathdefs[lastCommand.upper()][0].lower()
  109.             else:
  110.                 raise Exception, 'Invalid path, no initial command.'    
  111.         numParams = pathdefs[command.upper()][1]
  112.         while numParams > 0:
  113.             if needParam:
  114.                 try: 
  115.                     token, isCommand = lexer.next()
  116.                     if isCommand:
  117.                         raise Exception, 'Invalid number of parameters'
  118.                 except StopIteration:
  119.                     raise Exception, 'Unexpected end of path'
  120.             cast = pathdefs[command.upper()][2][-numParams]
  121.             param = cast(token)
  122.             if command.islower():
  123.                 if pathdefs[command.upper()][3][-numParams]=='x':
  124.                     param += pen[0]
  125.                 elif pathdefs[command.upper()][3][-numParams]=='y':
  126.                     param += pen[1]
  127.             params.append(param)
  128.             needParam = True
  129.             numParams -= 1
  130.         #segment is now absolute so
  131.         outputCommand = command.upper()
  132.     
  133.         #Flesh out shortcut notation    
  134.         if outputCommand in ('H','V'):
  135.             if outputCommand == 'H':
  136.                 params.append(pen[1])
  137.             if outputCommand == 'V':
  138.                 params.insert(0,pen[0])
  139.             outputCommand = 'L'
  140.         if outputCommand in ('S','T'):
  141.             params.insert(0,pen[1]+(pen[1]-lastControl[1]))
  142.             params.insert(0,pen[0]+(pen[0]-lastControl[0]))
  143.             if outputCommand == 'S':
  144.                 outputCommand = 'C'
  145.             if outputCommand == 'T':
  146.                 outputCommand = 'Q'
  147.  
  148.         #current values become "last" values
  149.         if outputCommand == 'M':
  150.             subPathStart = tuple(params[0:2])
  151.             pen = subPathStart
  152.         if outputCommand == 'Z':
  153.             pen = subPathStart
  154.         else:
  155.             pen = tuple(params[-2:])
  156.  
  157.         if outputCommand in ('Q','C'):
  158.             lastControl = tuple(params[-4:-2])
  159.         else:
  160.             lastControl = pen
  161.         lastCommand = command
  162.  
  163.         retval.append([outputCommand,params])
  164.     return retval
  165.  
  166. def formatPath(a):
  167.     """Format SVG path data from an array"""
  168.     return "".join([cmd + " ".join([str(p) for p in params]) for cmd, params in a])
  169.  
  170. def translatePath(p, x, y):
  171.     for cmd,params in p:
  172.         defs = pathdefs[cmd]
  173.         for i in range(defs[1]):
  174.             if defs[3][i] == 'x':
  175.                 params[i] += x
  176.             elif defs[3][i] == 'y':
  177.                 params[i] += y
  178.  
  179. def scalePath(p, x, y):
  180.     for cmd,params in p:
  181.         defs = pathdefs[cmd]
  182.         for i in range(defs[1]):
  183.             if defs[3][i] == 'x':
  184.                 params[i] *= x
  185.             elif defs[3][i] == 'y':
  186.                 params[i] *= y
  187.             elif defs[3][i] == 'r':         # radius parameter
  188.                 params[i] *= x
  189.             elif defs[3][i] == 's':         # sweep-flag parameter
  190.                 if x*y < 0:
  191.                     params[i] = 1 - params[i]
  192.             elif defs[3][i] == 'a':         # x-axis-rotation angle
  193.                 if y < 0:
  194.                     params[i] = - params[i]
  195.  
  196. def rotatePath(p, a, cx = 0, cy = 0):
  197.     if a == 0:
  198.         return p
  199.     for cmd,params in p:
  200.         defs = pathdefs[cmd]
  201.         for i in range(defs[1]):
  202.             if defs[3][i] == 'x':
  203.                 x = params[i] - cx
  204.                 y = params[i + 1] - cy
  205.                 r = math.sqrt((x**2) + (y**2))
  206.                 if r != 0:
  207.                     theta = math.atan2(y, x) + a
  208.                     params[i] = (r * math.cos(theta)) + cx
  209.                     params[i + 1] = (r * math.sin(theta)) + cy
  210.  
  211.  
  212. # vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 encoding=utf-8 textwidth=99
  213.