1 import math
, cmath
, sys
, copy
, new
, warnings
6 ############################### copy-and-convert versions of main operations
11 obj
= copy
.deepcopy(obj
)
15 def transform(trans
, obj
):
16 if isinstance(trans
, basestring
):
17 trans
= svg
.cannonical_transformation(trans
)
19 obj
= copy
.deepcopy(obj
)
23 for t
in trans
: obj
.transform(t
)
27 obj
= copy
.copy(obj
) # start with a shallow copy
28 if isinstance(obj
, svg
.SVG
) and obj
.tag
is None:
32 obj
.__dict
__["attrib"] = copy
.deepcopy(obj
.__dict
__["attrib"])
35 for i
in xrange(len(obj
.children
)):
36 obj
.children
[i
] = evaluate(obj
.children
[i
])
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
50 if len(self
.children
) == 1:
51 return "<Freeze (1 child)>"
53 return "<Freeze (%d children)>" % len(self
.children
)
55 def transform(self
, trans
): pass
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
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"] = []
73 if len(self
.children
) == 1:
74 return "<Delay (1 child) (%d trans)>" % len(self
.trans
)
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
))
83 return self
._svg
.bbox()
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
__)
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]:
106 if "z" in code
.co_names
:
107 context
.update(cmath
.__dict
__)
109 context
.update(math
.__dict
__)
110 f
= new
.function(code
, context
)
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
125 def __init__(self
, x
, y
, *args
, **kwds
):
126 self
.__dict
__["x"] = x
127 self
.__dict
__["y"] = y
129 self
.__dict
__["rotate"] = kwds
["rotate"]
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
141 if self
.rotate
: rotate
= "and rotate "
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
)
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
__)
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
)
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
)
177 if scale
!= 0.: eps
*= scale
179 xprime
, yprime
= func(x
+ eps
, 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
)
188 if scale
!= 0.: eps
*= scale
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):
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
= "", ""
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
)}
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
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
)}
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
)
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
)