root/trunk/RBRapier/RBRapier/Formats/SVG/SVGSkin/SVGItems/TransformBuilder.py

Revision 658, 5.8 kB (checked in by sholloway, 5 years ago)

*** empty log message ***

Line 
1 #!/usr/bin/env python
2 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 ##~ License
4 ##~
5 ##- The RuneBlade Foundation library is intended to ease some
6 ##- aspects of writing intricate Jabber, XML, and User Interface (wxPython, etc.)
7 ##- applications, while providing the flexibility to modularly change the
8 ##- architecture. Enjoy.
9 ##~
10 ##~ Copyright (C) 2002  TechGame Networks, LLC.
11 ##~
12 ##~ This library is free software; you can redistribute it and/or
13 ##~ modify it under the terms of the BSD style License as found in the
14 ##~ LICENSE file included with this distribution.
15 ##~
16 ##~ TechGame Networks, LLC can be reached at:
17 ##~ 3578 E. Hartsel Drive #211
18 ##~ Colorado Springs, Colorado, USA, 80920
19 ##~
20 ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
21
22 """
23 Translate commands
24
25     translate(x=0, y=0)
26     scale(x=1, y=x)
27     rotate(angle, x=0, y=0)
28     skewX(angle)
29     skewY(angle)
30     matrix(xx, xy, yx, yy)
31 """
32
33 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
34 #~ Imports
35 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
36
37 import re
38
39 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
40 #~ Definitions
41 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
42
43 def _transformcommand(name, argtypes):
44     return {'name':name, 'argtypes':argtypes}
45
46 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
47 #~ Transform Factories
48 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
49
50 class AbstractTransformFactory(object):
51     __slots__ = ()
52
53     def BeginTransform(self, transformcmd):
54         raise NotImplementedError
55     def AddTransformElement(self, name, *args):
56         raise NotImplementedError
57     def EndTransform(self, transformcmd):
58         raise NotImplementedError
59
60     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
61
62     #def translate(self, x=0.0, y=0.0):
63     #    raise NotImplementedError
64     #def scale(self, x=1., y=x):
65     #    raise NotImplementedError
66     #def rotate(self, angle=0.0, x=0, y=0):
67     #    raise NotImplementedError
68     #def skewx(self, angle=0.0):
69     #    raise NotImplementedError
70     #def skewy(self, angle=0.0):
71     #    raise NotImplementedError
72     #def matrix(self, xx=1.0, xy=0.0, xh=0.0, yx=0.0, yy=1.0, yh=0.0, hx=0.0, hy=0.0, hh=1.0):
73     #    raise NotImplementedError
74
75 class SaveTransformFactory(AbstractTransformFactory):
76     __slots__ = ('transformcmd', 'transforms')
77
78     def BeginTransform(self, transformcmd):
79         self.transformcmd = transformcmd
80         self.transforms = []
81
82     def AddTransformElement(self, *args):
83         self.transforms.append(args)
84        
85     def EndTransform(self, transformcmd):
86         assert self.transformcmd is transformcmd
87
88     def RestoreTo(self, transformfactory):
89         self.RestoreToEx(
90             onbegin=transformfactory.BeginTransform,
91             onadd=transformfactory.AddTransformElement,
92             onend=transformfactory.EndTransform)
93         return transformfactory
94
95     def RestoreToEx(self, onbegin=lambda xformcmd:None, onadd=lambda name, *args:None, onend=lambda xformcmd:None):
96         onbegin(self.transformcmd)
97         for args in self.transforms:
98             onadd(*args)
99         onend(self.transformcmd)
100
101 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
102 #~ Transform Builder/Interpreter
103 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
104
105 class TransformCommandBuilder(object):
106     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
107     #~ Constants / Variables / Etc.
108     #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
109
110     _delim = '\s*,?\s*'
111     _re_command = re.compile(r'\s*(\w+)\s*\(([^\)]*)\)\s*')
112     _re_argument = re.compile(r'([-+]?(?:\d+(?:\.\d*)?|\d*\.\d+)(?:[eE][-+]?\d+)?)'+_delim)
113
114     def __init__(self, transformfactory=None):
115         self.transformfactory = transformfactory
116
117     def Build(self, transformcmd, transformfactory=None):
118         transformfactory = transformfactory or self.transformfactory
119
120         transformfactory.BeginTransform(transformcmd)
121
122         matchidx = 0
123         # MoveTo is the default command
124         while matchidx < len(transformcmd):
125             # Find out what command we're dealing with
126             commandmatch = self._re_command.match(transformcmd, matchidx)
127             assert commandmatch is not None
128             command, args = commandmatch.groups()
129             matchidx = commandmatch.end()
130
131             # parse out the arguments for the transform element
132             arguments = []
133             args = args.strip()
134             while args:
135                 argmatch = self._re_argument.match(args)
136                 arguments.extend(map(float, argmatch.groups()))
137                 args = args[argmatch.end():]
138
139             # go get the transform factory method for our command
140             transformfactory.AddTransformElement(command, *arguments)
141
142         transformfactory.EndTransform(transformcmd)
143         return transformfactory
144
145 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
146 #~ Testing
147 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
148
149 if __name__=='__main__':
150     class TestTransformFactory(AbstractTransformFactory):
151         def __iter__(self):
152             return iter(self.results)
153         def BeginTransform(self, pathstr):
154             self.results = ["begin()"]
155         def AddTransformElement(self, name, *args):
156             self.results.append('%s%r' % (name, args))
157         def EndTransform(self, pathstr):
158             self.results.append("end()")
159
160     builder = TransformCommandBuilder(TestTransformFactory())
161
162     print
163     print "Example 1:"
164     for each in builder.Build('scale(2, 3)'):
165         print '   ', each
166
167     print
168     print "Example 2:"
169     for each in builder.Build('translate(-3, 4)'):
170         print '   ', each
171
172     print
173     print "Example 3:"
174     for each in builder.Build('translate(-3, 4) scale(3)'):
175         print '   ', each
176
177     print
178     print "Example 4:"
179     for each in builder.Build('scale(.5-4)skewx(3)'):
180         print '   ', each
181
Note: See TracBrowser for help on using the browser.