Reset platonic code.
[voro++.git] / branches / 2d_boundary / Tests / svgfig / trans.py
blob40b38f60b952524ffa44c712c35adb3b6f78df2f
1 import math, cmath, sys, copy, new, warnings
2 import svg, defaults
4 epsilon = 1e-5
6 ############################### copy-and-convert versions of main operations
8 clone = copy.deepcopy
10 def tonumber(obj):
11 obj = copy.deepcopy(obj)
12 obj.tonumber()
13 return obj
15 def transform(trans, obj):
16 if isinstance(trans, basestring):
17 trans = svg.cannonical_transformation(trans)
19 obj = copy.deepcopy(obj)
20 if callable(trans):
21 obj.transform(trans)
22 else:
23 for t in trans: obj.transform(t)
24 return obj
26 def evaluate(obj):
27 obj = copy.copy(obj) # start with a shallow copy
28 if isinstance(obj, svg.SVG) and obj.tag is None:
29 obj.svg()
30 obj = obj._svg
32 obj.__dict__["attrib"] = copy.deepcopy(obj.__dict__["attrib"])
34 replacements = {}
35 for i in xrange(len(obj.children)):
36 obj.children[i] = evaluate(obj.children[i])
38 return obj
40 ############################### groups with special transformation properties
42 class Freeze(svg.SVG):
43 def __init__(self, *args, **kwds):
44 self.__dict__["tag"] = None
45 self.__dict__["attrib"] = kwds
46 self.__dict__["children"] = list(args)
47 self.__dict__["_svg"] = None
49 def __repr__(self):
50 if len(self.children) == 1:
51 return "<Freeze (1 child)>"
52 else:
53 return "<Freeze (%d children)>" % len(self.children)
55 def transform(self, trans): pass
57 def svg(self):
58 self._svg = new.instance(svg.SVG)
59 self._svg.__dict__["tag"] = "g"
60 self._svg.__dict__["attrib"] = self.attrib
61 self._svg.__dict__["children"] = self.children
62 self._svg.__dict__["_svg"] = self._svg
64 class Delay(svg.SVG):
65 def __init__(self, *args, **kwds):
66 self.__dict__["tag"] = None
67 self.__dict__["attrib"] = kwds
68 self.__dict__["children"] = list(args)
69 self.__dict__["_svg"] = None
70 self.__dict__["trans"] = []
72 def __repr__(self):
73 if len(self.children) == 1:
74 return "<Delay (1 child) (%d trans)>" % len(self.trans)
75 else:
76 return "<Delay (%d children) (%d trans)>" % (len(self.children), len(self.trans))
78 def transform(self, trans):
79 self.trans.append(svg.cannonical_transformation(trans))
81 def bbox(self):
82 self.svg()
83 return self._svg.bbox()
85 def svg(self):
86 self._svg = new.instance(svg.SVG)
87 self._svg.__dict__["tag"] = "g"
88 self._svg.__dict__["attrib"] = self.attrib
89 self._svg.__dict__["_svg"] = self._svg
91 self._svg.__dict__["children"] = []
92 for child in self.children:
93 self._svg.__dict__["children"].append(transform(self.trans, child))
95 def __getstate__(self):
96 mostdict = copy.copy(self.__dict__)
97 del mostdict["trans"]
98 transcode = map(lambda f: (f.func_code, f.func_name), self.trans)
99 return (sys.version_info, defaults.version_info, mostdict, transcode)
101 def __setstate__(self, state):
102 self.__dict__ = state[2]
103 self.__dict__["trans"] = []
104 for code, name in state[3]:
105 context = globals()
106 if "z" in code.co_names:
107 context.update(cmath.__dict__)
108 else:
109 context.update(math.__dict__)
110 f = new.function(code, context)
111 f.func_name = name
112 self.__dict__["trans"].append(f)
114 def __deepcopy__(self, memo={}):
115 mostdict = copy.copy(self.__dict__)
116 del mostdict["trans"]
117 if "repr" in mostdict: del mostdict["repr"]
118 output = new.instance(self.__class__)
119 output.__dict__ = copy.deepcopy(mostdict, memo)
120 output.__dict__["trans"] = copy.copy(self.trans)
121 memo[id(self)] = output
122 return output
124 class Pin(svg.SVG):
125 def __init__(self, x, y, *args, **kwds):
126 self.__dict__["x"] = x
127 self.__dict__["y"] = y
128 if "rotate" in kwds:
129 self.__dict__["rotate"] = kwds["rotate"]
130 del kwds["rotate"]
131 else:
132 self.__dict__["rotate"] = False
134 self.__dict__["tag"] = None
135 self.__dict__["attrib"] = kwds
136 self.__dict__["children"] = list(args)
137 self.__dict__["_svg"] = None
139 def __repr__(self):
140 rotate = ""
141 if self.rotate: rotate = "and rotate "
142 ren = "ren"
143 if len(self.children) == 1: ren = ""
145 return "<Pin %sat %g %g (%d child%s)>" % (rotate, self.x, self.y, len(self.children), ren)
147 def transform(self, trans):
148 trans = svg.cannonical_transformation(trans)
150 oldx, oldy = self.x, self.y
151 self.x, self.y = trans(self.x, self.y)
153 if self.rotate:
154 shiftx, shifty = trans(oldx + epsilon, oldy)
155 angle = math.atan2(shifty, shiftx)
156 trans = eval("lambda x, y: (%(newx)s + cos(%(angle)s)*(x - %(oldx)s) - sin(%(angle)s)*(y - %(oldy)s), %(newy)s + sin(%(angle)s)*(x - %(oldx)s) + cos(%(angle)s)*(y - %(oldy)s))" % {"newx": repr(self.x), "newy": repr(self.y), "oldx": repr(oldx), "oldy": repr(oldy), "angle": repr(angle)}, math.__dict__)
158 else:
159 trans = eval("lambda x, y: (x + %(newx)s - %(oldx)s, y + %(newy)s - %(oldy)s)" %
160 {"newx": repr(self.x), "newy": repr(self.y), "oldx": repr(oldx), "oldy": repr(oldy)})
162 for child in self.children:
163 if isinstance(child, svg.SVG): child.transform(trans)
165 def svg(self):
166 self._svg = new.instance(svg.SVG)
167 self._svg.__dict__["tag"] = "g"
168 self._svg.__dict__["attrib"] = self.attrib
169 self._svg.__dict__["children"] = self.children
170 self._svg.__dict__["_svg"] = self._svg
172 ############################### operations on transformations
174 def transformation_angle(expr, x, y, scale=1.):
175 func = svg.cannonical_transformation(expr)
176 eps = epsilon
177 if scale != 0.: eps *= scale
179 xprime, yprime = func(x + eps, y)
180 x, y = func(x, y)
182 delx, dely = xprime - x, yprime - y
183 return math.atan2(dely, delx)
185 def transformation_jacobian(expr, x, y, scale=1.):
186 func = svg.cannonical_transformation(expr)
187 eps = epsilon
188 if scale != 0.: eps *= scale
190 X0, Y0 = func(x, y)
191 xhatx, xhaty = func(x + eps, y)
192 yhatx, yhaty = func(x, y + eps)
194 return (1.*(xhatx - X0)/eps, 1.*(xhaty - Y0)/eps), (1.*(yhatx - X0)/eps, 1.*(yhaty - Y0)/eps)
196 ############################### standard transformations
198 def window(xmin, xmax, ymin, ymax, x=0, y=0, width=100, height=100, xlogbase=None, ylogbase=None, minusInfinityX=-1000, minusInfinityY=-1000, flipx=False, flipy=False):
199 if flipx:
200 ox1 = x + width
201 ox2 = x
202 else:
203 ox1 = x
204 ox2 = x + width
205 if flipy:
206 oy1 = y + height
207 oy2 = y
208 else:
209 oy1 = y
210 oy2 = y + height
211 ix1 = xmin
212 iy1 = ymin
213 ix2 = xmax
214 iy2 = ymax
216 if xlogbase != None and (ix1 <= 0. or ix2 <= 0.): raise ValueError, "x range incompatible with log scaling: (%g, %g)" % (ix1, ix2)
218 if ylogbase != None and (iy1 <= 0. or iy2 <= 0.): raise ValueError, "y range incompatible with log scaling: (%g, %g)" % (iy1, iy2)
220 xlogstr, ylogstr = "", ""
222 if xlogbase == None:
223 xfunc = "%(ox1)s + 1.*(x - %(ix1)s)/(%(ix2)s - %(ix1)s) * (%(ox2)s - %(ox1)s)" % \
224 {"ox1": repr(ox1), "ox2": repr(ox2), "ix1": repr(ix1), "ix2": repr(ix2)}
225 else:
226 xfunc = "x <= 0 and %(minusInfinityX)s or %(ox1)s + 1.*(log(x, %(logbase)s) - log(%(ix1)s, %(logbase)s))/(log(%(ix2)s, %(logbase)s) - log(%(ix1)s, %(logbase)s)) * (%(ox2)s - %(ox1)s)" % \
227 {"ox1": repr(ox1), "ox2": repr(ox2), "ix1": repr(ix1), "ix2": repr(ix2), "minusInfinityX": repr(minusInfinityX), "logbase": xlogbase}
228 xlogstr = " xlog=%g" % xlogbase
230 if ylogbase == None:
231 yfunc = "%(oy1)s + 1.*(y - %(iy1)s)/(%(iy2)s - %(iy1)s) * (%(oy2)s - %(oy1)s)" % \
232 {"oy1": repr(oy1), "oy2": repr(oy2), "iy1": repr(iy1), "iy2": repr(iy2)}
233 else:
234 yfunc = "y <= 0 and %(minusInfinityY)s or %(oy1)s + 1.*(log(y, %(logbase)s) - log(%(iy1)s, %(logbase)s))/(log(%(iy2)s, %(logbase)s) - log(%(iy1)s, %(logbase)s)) * (%(oy2)s - %(oy1)s)" % \
235 {"oy1": repr(oy1), "oy2": repr(oy2), "iy1": repr(iy1), "iy2": repr(iy2), "minusInfinityY": repr(minusInfinityY), "logbase": ylogbase}
236 ylogstr = " ylog=%g" % ylogbase
238 output = eval("lambda x,y: (%s, %s)" % (xfunc, yfunc), math.__dict__)
239 output.func_name = "(%g, %g), (%g, %g) -> (%g, %g), (%g, %g)%s%s" % (ix1, ix2, iy1, iy2, ox1, ox2, oy1, oy2, xlogstr, ylogstr)
240 return output
242 def rotation(angle, cx=0, cy=0):
243 output = eval("lambda x,y: (%(cx)s + cos(%(angle)s)*(x - %(cx)s) - sin(%(angle)s)*(y - %(cy)s), %(cy)s + sin(%(angle)s)*(x - %(cx)s) + cos(%(angle)s)*(y - %(cy)s))" % {"cx": repr(cx), "cy": repr(cy), "angle": repr(angle)}, math.__dict__)
244 output.func_name = "rotation %g around %g %g" % (angle, cx, cy)
245 return output