1f184f754862637ad9c3c32952a0756414e2b67a6jvr"""Affine 2D transformation matrix class.
2f184f754862637ad9c3c32952a0756414e2b67a6jvr
3f184f754862637ad9c3c32952a0756414e2b67a6jvrThe Transform class implements various transformation matrix operations,
4f184f754862637ad9c3c32952a0756414e2b67a6jvrboth on the matrix itself, as well as on 2D coordinates.
5f184f754862637ad9c3c32952a0756414e2b67a6jvr
6f184f754862637ad9c3c32952a0756414e2b67a6jvrTransform instances are effectively immutable: all methods that operate on the
7f184f754862637ad9c3c32952a0756414e2b67a6jvrtransformation itself always return a new instance. This has as the
8f184f754862637ad9c3c32952a0756414e2b67a6jvrinteresting side effect that Transform instances are hashable, ie. they can be
9f184f754862637ad9c3c32952a0756414e2b67a6jvrused as dictionary keys.
10f184f754862637ad9c3c32952a0756414e2b67a6jvr
11f184f754862637ad9c3c32952a0756414e2b67a6jvrThis module exports the following symbols:
12f184f754862637ad9c3c32952a0756414e2b67a6jvr
13f184f754862637ad9c3c32952a0756414e2b67a6jvr	Transform -- this is the main class
14f184f754862637ad9c3c32952a0756414e2b67a6jvr	Identity  -- Transform instance set to the identity transformation
15f184f754862637ad9c3c32952a0756414e2b67a6jvr	Offset    -- Convenience function that returns a translating transformation
16f184f754862637ad9c3c32952a0756414e2b67a6jvr	Scale     -- Convenience function that returns a scaling transformation
17f184f754862637ad9c3c32952a0756414e2b67a6jvr
18f184f754862637ad9c3c32952a0756414e2b67a6jvrExamples:
19f184f754862637ad9c3c32952a0756414e2b67a6jvr
20f184f754862637ad9c3c32952a0756414e2b67a6jvr	>>> t = Transform(2, 0, 0, 3, 0, 0)
21f184f754862637ad9c3c32952a0756414e2b67a6jvr	>>> t.transformPoint((100, 100))
22f184f754862637ad9c3c32952a0756414e2b67a6jvr	(200, 300)
23f184f754862637ad9c3c32952a0756414e2b67a6jvr	>>> t = Scale(2, 3)
24f184f754862637ad9c3c32952a0756414e2b67a6jvr	>>> t.transformPoint((100, 100))
25f184f754862637ad9c3c32952a0756414e2b67a6jvr	(200, 300)
26f184f754862637ad9c3c32952a0756414e2b67a6jvr	>>> t.transformPoint((0, 0))
27f184f754862637ad9c3c32952a0756414e2b67a6jvr	(0, 0)
28f184f754862637ad9c3c32952a0756414e2b67a6jvr	>>> t = Offset(2, 3)
29f184f754862637ad9c3c32952a0756414e2b67a6jvr	>>> t.transformPoint((100, 100))
30f184f754862637ad9c3c32952a0756414e2b67a6jvr	(102, 103)
31f184f754862637ad9c3c32952a0756414e2b67a6jvr	>>> t.transformPoint((0, 0))
32f184f754862637ad9c3c32952a0756414e2b67a6jvr	(2, 3)
33f184f754862637ad9c3c32952a0756414e2b67a6jvr	>>> t2 = t.scale(0.5)
34f184f754862637ad9c3c32952a0756414e2b67a6jvr	>>> t2.transformPoint((100, 100))
35f184f754862637ad9c3c32952a0756414e2b67a6jvr	(52.0, 53.0)
36f184f754862637ad9c3c32952a0756414e2b67a6jvr	>>> import math
37f184f754862637ad9c3c32952a0756414e2b67a6jvr	>>> t3 = t2.rotate(math.pi / 2)
38f184f754862637ad9c3c32952a0756414e2b67a6jvr	>>> t3.transformPoint((0, 0))
39f184f754862637ad9c3c32952a0756414e2b67a6jvr	(2.0, 3.0)
40f184f754862637ad9c3c32952a0756414e2b67a6jvr	>>> t3.transformPoint((100, 100))
41f184f754862637ad9c3c32952a0756414e2b67a6jvr	(-48.0, 53.0)
42f184f754862637ad9c3c32952a0756414e2b67a6jvr	>>> t = Identity.scale(0.5).translate(100, 200).skew(0.1, 0.2)
43f184f754862637ad9c3c32952a0756414e2b67a6jvr	>>> t.transformPoints([(0, 0), (1, 1), (100, 100)])
44f184f754862637ad9c3c32952a0756414e2b67a6jvr	[(50.0, 100.0), (50.550167336042726, 100.60135501775433), (105.01673360427253, 160.13550177543362)]
45f184f754862637ad9c3c32952a0756414e2b67a6jvr	>>>
46f184f754862637ad9c3c32952a0756414e2b67a6jvr"""
47f184f754862637ad9c3c32952a0756414e2b67a6jvr
481ae29591efbb29492ce05378909ccf4028d7c1eeBehdad Esfahbodfrom __future__ import print_function, division, absolute_import
4930e691edd056ba22fa8970280e986747817bec3dBehdad Esfahbodfrom fontTools.misc.py23 import *
50f184f754862637ad9c3c32952a0756414e2b67a6jvr
51f184f754862637ad9c3c32952a0756414e2b67a6jvr__all__ = ["Transform", "Identity", "Offset", "Scale"]
529e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr
539e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr
549e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr_EPSILON = 1e-15
559e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr_ONE_EPSILON = 1 - _EPSILON
569e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr_MINUS_ONE_EPSILON = -1 + _EPSILON
579e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr
589e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr
599e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvrdef _normSinCos(v):
609e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr	if abs(v) < _EPSILON:
619e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		v = 0
629e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr	elif v > _ONE_EPSILON:
639e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		v = 1
649e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr	elif v < _MINUS_ONE_EPSILON:
659e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		v = -1
669e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr	return v
679e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr
689e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr
69e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass Transform(object):
706385a4e9e16560212857b5eade6d0015f729a0b3jvr
719e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr	"""2x2 transformation matrix plus offset, a.k.a. Affine transform.
72f184f754862637ad9c3c32952a0756414e2b67a6jvr	Transform instances are immutable: all transforming methods, eg.
73f184f754862637ad9c3c32952a0756414e2b67a6jvr	rotate(), return a new Transform instance.
74f184f754862637ad9c3c32952a0756414e2b67a6jvr
75f184f754862637ad9c3c32952a0756414e2b67a6jvr	Examples:
76f184f754862637ad9c3c32952a0756414e2b67a6jvr		>>> t = Transform()
77f184f754862637ad9c3c32952a0756414e2b67a6jvr		>>> t
78f184f754862637ad9c3c32952a0756414e2b67a6jvr		<Transform [1 0 0 1 0 0]>
79f184f754862637ad9c3c32952a0756414e2b67a6jvr		>>> t.scale(2)
80f184f754862637ad9c3c32952a0756414e2b67a6jvr		<Transform [2 0 0 2 0 0]>
81f184f754862637ad9c3c32952a0756414e2b67a6jvr		>>> t.scale(2.5, 5.5)
82f184f754862637ad9c3c32952a0756414e2b67a6jvr		<Transform [2.5 0.0 0.0 5.5 0 0]>
83f184f754862637ad9c3c32952a0756414e2b67a6jvr		>>>
84f184f754862637ad9c3c32952a0756414e2b67a6jvr		>>> t.scale(2, 3).transformPoint((100, 100))
85f184f754862637ad9c3c32952a0756414e2b67a6jvr		(200, 300)
86f184f754862637ad9c3c32952a0756414e2b67a6jvr	"""
876385a4e9e16560212857b5eade6d0015f729a0b3jvr
889e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr	def __init__(self, xx=1, xy=0, yx=0, yy=1, dx=0, dy=0):
89deca398915e92f24fe698e2e7d0e13122f61383ejvr		"""Transform's constructor takes six arguments, all of which are
90deca398915e92f24fe698e2e7d0e13122f61383ejvr		optional, and can be used as keyword arguments:
91deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>> Transform(12)
92deca398915e92f24fe698e2e7d0e13122f61383ejvr			<Transform [12 0 0 1 0 0]>
93deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>> Transform(dx=12)
94deca398915e92f24fe698e2e7d0e13122f61383ejvr			<Transform [1 0 0 1 12 0]>
95deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>> Transform(yx=12)
96deca398915e92f24fe698e2e7d0e13122f61383ejvr			<Transform [1 0 12 1 0 0]>
97deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>>
98deca398915e92f24fe698e2e7d0e13122f61383ejvr		"""
999e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		self.__affine = xx, xy, yx, yy, dx, dy
1006385a4e9e16560212857b5eade6d0015f729a0b3jvr
1013a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod	def transformPoint(self, p):
102f184f754862637ad9c3c32952a0756414e2b67a6jvr		"""Transform a point.
103f184f754862637ad9c3c32952a0756414e2b67a6jvr
104f184f754862637ad9c3c32952a0756414e2b67a6jvr		Example:
105f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>> t = Transform()
106f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>> t = t.scale(2.5, 5.5)
107f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>> t.transformPoint((100, 100))
108f184f754862637ad9c3c32952a0756414e2b67a6jvr			(250.0, 550.0)
109f184f754862637ad9c3c32952a0756414e2b67a6jvr		"""
1103a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod		(x, y) = p
1119e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		xx, xy, yx, yy, dx, dy = self.__affine
1129e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		return (xx*x + yx*y + dx, xy*x + yy*y + dy)
1136385a4e9e16560212857b5eade6d0015f729a0b3jvr
114f184f754862637ad9c3c32952a0756414e2b67a6jvr	def transformPoints(self, points):
115f184f754862637ad9c3c32952a0756414e2b67a6jvr		"""Transform a list of points.
116f184f754862637ad9c3c32952a0756414e2b67a6jvr
117f184f754862637ad9c3c32952a0756414e2b67a6jvr		Example:
118f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>> t = Scale(2, 3)
119f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>> t.transformPoints([(0, 0), (0, 100), (100, 100), (100, 0)])
120f184f754862637ad9c3c32952a0756414e2b67a6jvr			[(0, 0), (0, 300), (200, 300), (200, 0)]
121f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>>
122f184f754862637ad9c3c32952a0756414e2b67a6jvr		"""
123f184f754862637ad9c3c32952a0756414e2b67a6jvr		xx, xy, yx, yy, dx, dy = self.__affine
124f184f754862637ad9c3c32952a0756414e2b67a6jvr		return [(xx*x + yx*y + dx, xy*x + yy*y + dy) for x, y in points]
125f184f754862637ad9c3c32952a0756414e2b67a6jvr
1269e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr	def translate(self, x=0, y=0):
127f184f754862637ad9c3c32952a0756414e2b67a6jvr		"""Return a new transformation, translated (offset) by x, y.
128f184f754862637ad9c3c32952a0756414e2b67a6jvr
129f184f754862637ad9c3c32952a0756414e2b67a6jvr		Example:
130f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>> t = Transform()
131f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>> t.translate(20, 30)
132f184f754862637ad9c3c32952a0756414e2b67a6jvr			<Transform [1 0 0 1 20 30]>
133f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>>
134f184f754862637ad9c3c32952a0756414e2b67a6jvr		"""
1359e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		return self.transform((1, 0, 0, 1, x, y))
1366385a4e9e16560212857b5eade6d0015f729a0b3jvr
1379e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr	def scale(self, x=1, y=None):
138f184f754862637ad9c3c32952a0756414e2b67a6jvr		"""Return a new transformation, scaled by x, y. The 'y' argument
139f184f754862637ad9c3c32952a0756414e2b67a6jvr		may be None, which implies to use the x value for y as well.
140f184f754862637ad9c3c32952a0756414e2b67a6jvr
141f184f754862637ad9c3c32952a0756414e2b67a6jvr		Example:
142f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>> t = Transform()
143f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>> t.scale(5)
144f184f754862637ad9c3c32952a0756414e2b67a6jvr			<Transform [5 0 0 5 0 0]>
145f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>> t.scale(5, 6)
146f184f754862637ad9c3c32952a0756414e2b67a6jvr			<Transform [5 0 0 6 0 0]>
147f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>>
148f184f754862637ad9c3c32952a0756414e2b67a6jvr		"""
1499e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		if y is None:
1509e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr			y = x
1519e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		return self.transform((x, 0, 0, y, 0, 0))
1526385a4e9e16560212857b5eade6d0015f729a0b3jvr
1539e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr	def rotate(self, angle):
154f184f754862637ad9c3c32952a0756414e2b67a6jvr		"""Return a new transformation, rotated by 'angle' (radians).
155f184f754862637ad9c3c32952a0756414e2b67a6jvr
156f184f754862637ad9c3c32952a0756414e2b67a6jvr		Example:
157f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>> import math
158f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>> t = Transform()
159f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>> t.rotate(math.pi / 2)
160f184f754862637ad9c3c32952a0756414e2b67a6jvr			<Transform [0 1 -1 0 0 0]>
161f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>>
162f184f754862637ad9c3c32952a0756414e2b67a6jvr		"""
1639e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		import math
1649e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		c = _normSinCos(math.cos(angle))
1659e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		s = _normSinCos(math.sin(angle))
1669e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		return self.transform((c, s, -s, c, 0, 0))
1676385a4e9e16560212857b5eade6d0015f729a0b3jvr
1689e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr	def skew(self, x=0, y=0):
169f184f754862637ad9c3c32952a0756414e2b67a6jvr		"""Return a new transformation, skewed by x and y.
170f184f754862637ad9c3c32952a0756414e2b67a6jvr
171f184f754862637ad9c3c32952a0756414e2b67a6jvr		Example:
172f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>> import math
173f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>> t = Transform()
174f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>> t.skew(math.pi / 4)
175f184f754862637ad9c3c32952a0756414e2b67a6jvr			<Transform [1.0 0.0 1.0 1.0 0 0]>
176f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>>
177f184f754862637ad9c3c32952a0756414e2b67a6jvr		"""
1789e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		import math
1799e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		return self.transform((1, math.tan(y), math.tan(x), 1, 0, 0))
1806385a4e9e16560212857b5eade6d0015f729a0b3jvr
1819e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr	def transform(self, other):
182f184f754862637ad9c3c32952a0756414e2b67a6jvr		"""Return a new transformation, transformed by another
183f184f754862637ad9c3c32952a0756414e2b67a6jvr		transformation.
184f184f754862637ad9c3c32952a0756414e2b67a6jvr
185f184f754862637ad9c3c32952a0756414e2b67a6jvr		Example:
186f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>> t = Transform(2, 0, 0, 3, 1, 6)
187f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>> t.transform((4, 3, 2, 1, 5, 6))
188f184f754862637ad9c3c32952a0756414e2b67a6jvr			<Transform [8 9 4 3 11 24]>
189f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>>
190f184f754862637ad9c3c32952a0756414e2b67a6jvr		"""
1919e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		xx1, xy1, yx1, yy1, dx1, dy1 = other
1929e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		xx2, xy2, yx2, yy2, dx2, dy2 = self.__affine
1939e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		return self.__class__(
1949e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr				xx1*xx2 + xy1*yx2,
1959e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr				xx1*xy2 + xy1*yy2,
1969e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr				yx1*xx2 + yy1*yx2,
1979e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr				yx1*xy2 + yy1*yy2,
1989e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr				xx2*dx1 + yx2*dy1 + dx2,
1999e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr				xy2*dx1 + yy2*dy1 + dy2)
2006385a4e9e16560212857b5eade6d0015f729a0b3jvr
2019e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr	def reverseTransform(self, other):
202f184f754862637ad9c3c32952a0756414e2b67a6jvr		"""Return a new transformation, which is the other transformation
203f184f754862637ad9c3c32952a0756414e2b67a6jvr		transformed by self. self.reverseTransform(other) is equivalent to
204f184f754862637ad9c3c32952a0756414e2b67a6jvr		other.transform(self).
205f184f754862637ad9c3c32952a0756414e2b67a6jvr
206f184f754862637ad9c3c32952a0756414e2b67a6jvr		Example:
207f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>> t = Transform(2, 0, 0, 3, 1, 6)
208f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>> t.reverseTransform((4, 3, 2, 1, 5, 6))
209f184f754862637ad9c3c32952a0756414e2b67a6jvr			<Transform [8 6 6 3 21 15]>
210f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>> Transform(4, 3, 2, 1, 5, 6).transform((2, 0, 0, 3, 1, 6))
211f184f754862637ad9c3c32952a0756414e2b67a6jvr			<Transform [8 6 6 3 21 15]>
212f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>>
213f184f754862637ad9c3c32952a0756414e2b67a6jvr		"""
2149e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		xx1, xy1, yx1, yy1, dx1, dy1 = self.__affine
2159e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		xx2, xy2, yx2, yy2, dx2, dy2 = other
2169e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		return self.__class__(
2179e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr				xx1*xx2 + xy1*yx2,
2189e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr				xx1*xy2 + xy1*yy2,
2199e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr				yx1*xx2 + yy1*yx2,
2209e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr				yx1*xy2 + yy1*yy2,
2219e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr				xx2*dx1 + yx2*dy1 + dx2,
2229e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr				xy2*dx1 + yy2*dy1 + dy2)
2236385a4e9e16560212857b5eade6d0015f729a0b3jvr
2249e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr	def inverse(self):
225f184f754862637ad9c3c32952a0756414e2b67a6jvr		"""Return the inverse transformation.
226f184f754862637ad9c3c32952a0756414e2b67a6jvr
227f184f754862637ad9c3c32952a0756414e2b67a6jvr		Example:
228deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>> t = Identity.translate(2, 3).scale(4, 5)
229deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>> t.transformPoint((10, 20))
230deca398915e92f24fe698e2e7d0e13122f61383ejvr			(42, 103)
231deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>> it = t.inverse()
232deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>> it.transformPoint((42, 103))
233deca398915e92f24fe698e2e7d0e13122f61383ejvr			(10.0, 20.0)
234f184f754862637ad9c3c32952a0756414e2b67a6jvr			>>>
235f184f754862637ad9c3c32952a0756414e2b67a6jvr		"""
2369e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		if self.__affine == (1, 0, 0, 1, 0, 0):
2379e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr			return self
2389e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		xx, xy, yx, yy, dx, dy = self.__affine
23932c10eecffb4923e0721c395e4b80fb732543f18Behdad Esfahbod		det = xx*yy - yx*xy
2409e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		xx, xy, yx, yy = yy/det, -xy/det, -yx/det, xx/det
2419e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		dx, dy = -xx*dx - yx*dy, -xy*dx - yy*dy
2429e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		return self.__class__(xx, xy, yx, yy, dx, dy)
2436385a4e9e16560212857b5eade6d0015f729a0b3jvr
2449e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr	def toPS(self):
245deca398915e92f24fe698e2e7d0e13122f61383ejvr		"""Return a PostScript representation:
246deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>> t = Identity.scale(2, 3).translate(4, 5)
247deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>> t.toPS()
248deca398915e92f24fe698e2e7d0e13122f61383ejvr			'[2 0 0 3 8 15]'
249deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>>
250deca398915e92f24fe698e2e7d0e13122f61383ejvr		"""
2519e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		return "[%s %s %s %s %s %s]" % self.__affine
2526385a4e9e16560212857b5eade6d0015f729a0b3jvr
2539e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr	def __len__(self):
254deca398915e92f24fe698e2e7d0e13122f61383ejvr		"""Transform instances also behave like sequences of length 6:
255deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>> len(Identity)
256deca398915e92f24fe698e2e7d0e13122f61383ejvr			6
257deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>>
258deca398915e92f24fe698e2e7d0e13122f61383ejvr		"""
2599e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		return 6
2606385a4e9e16560212857b5eade6d0015f729a0b3jvr
2619e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr	def __getitem__(self, index):
262deca398915e92f24fe698e2e7d0e13122f61383ejvr		"""Transform instances also behave like sequences of length 6:
263deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>> list(Identity)
264deca398915e92f24fe698e2e7d0e13122f61383ejvr			[1, 0, 0, 1, 0, 0]
265deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>> tuple(Identity)
266deca398915e92f24fe698e2e7d0e13122f61383ejvr			(1, 0, 0, 1, 0, 0)
267deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>>
268deca398915e92f24fe698e2e7d0e13122f61383ejvr		"""
2699e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		return self.__affine[index]
2706385a4e9e16560212857b5eade6d0015f729a0b3jvr
2718ea6439d3b66c5acc246261d761d4375bcb7cfabBehdad Esfahbod	def __ne__(self, other):
2728ea6439d3b66c5acc246261d761d4375bcb7cfabBehdad Esfahbod		return not self.__eq__(other)
273b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod	def __eq__(self, other):
274b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod		"""Transform instances are comparable:
275b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod			>>> t1 = Identity.scale(2, 3).translate(4, 6)
276b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod			>>> t2 = Identity.translate(8, 18).scale(2, 3)
277b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod			>>> t1 == t2
278b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod			1
279b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod			>>>
280b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod
281b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod		But beware of floating point rounding errors:
282b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod			>>> t1 = Identity.scale(0.2, 0.3).translate(0.4, 0.6)
283b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod			>>> t2 = Identity.translate(0.08, 0.18).scale(0.2, 0.3)
284b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod			>>> t1
285b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod			<Transform [0.2 0.0 0.0 0.3 0.08 0.18]>
286b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod			>>> t2
287b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod			<Transform [0.2 0.0 0.0 0.3 0.08 0.18]>
288b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod			>>> t1 == t2
289b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod			0
290b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod			>>>
291b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod		"""
292b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod		xx1, xy1, yx1, yy1, dx1, dy1 = self.__affine
293b7fd2e19138b177403689bdd6989cfd2402aa2b3Behdad Esfahbod		xx2, xy2, yx2, yy2, dx2, dy2 = other
294af1c9968b2edc827ee9115355a72b3c56c4fbe61Denis Jacquerye		return (xx1, xy1, yx1, yy1, dx1, dy1) == \
295af1c9968b2edc827ee9115355a72b3c56c4fbe61Denis Jacquerye				(xx2, xy2, yx2, yy2, dx2, dy2)
2966385a4e9e16560212857b5eade6d0015f729a0b3jvr
2979e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr	def __hash__(self):
298deca398915e92f24fe698e2e7d0e13122f61383ejvr		"""Transform instances are hashable, meaning you can use them as
299deca398915e92f24fe698e2e7d0e13122f61383ejvr		keys in dictionaries:
300deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>> d = {Scale(12, 13): None}
301deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>> d
302deca398915e92f24fe698e2e7d0e13122f61383ejvr			{<Transform [12 0 0 13 0 0]>: None}
303deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>>
304deca398915e92f24fe698e2e7d0e13122f61383ejvr
305deca398915e92f24fe698e2e7d0e13122f61383ejvr		But again, beware of floating point rounding errors:
306deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>> t1 = Identity.scale(0.2, 0.3).translate(0.4, 0.6)
307deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>> t2 = Identity.translate(0.08, 0.18).scale(0.2, 0.3)
308deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>> t1
309deca398915e92f24fe698e2e7d0e13122f61383ejvr			<Transform [0.2 0.0 0.0 0.3 0.08 0.18]>
310deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>> t2
311deca398915e92f24fe698e2e7d0e13122f61383ejvr			<Transform [0.2 0.0 0.0 0.3 0.08 0.18]>
312deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>> d = {t1: None}
313deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>> d
314deca398915e92f24fe698e2e7d0e13122f61383ejvr			{<Transform [0.2 0.0 0.0 0.3 0.08 0.18]>: None}
315deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>> d[t2]
316deca398915e92f24fe698e2e7d0e13122f61383ejvr			Traceback (most recent call last):
317deca398915e92f24fe698e2e7d0e13122f61383ejvr			  File "<stdin>", line 1, in ?
318deca398915e92f24fe698e2e7d0e13122f61383ejvr			KeyError: <Transform [0.2 0.0 0.0 0.3 0.08 0.18]>
319deca398915e92f24fe698e2e7d0e13122f61383ejvr			>>>
320deca398915e92f24fe698e2e7d0e13122f61383ejvr		"""
3219e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		return hash(self.__affine)
3226385a4e9e16560212857b5eade6d0015f729a0b3jvr
3239e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr	def __repr__(self):
324af1c9968b2edc827ee9115355a72b3c56c4fbe61Denis Jacquerye		return "<%s [%s %s %s %s %s %s]>" % ((self.__class__.__name__,) \
3259e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr				 + tuple(map(str, self.__affine)))
3269e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr
3279e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr
3289e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvrIdentity = Transform()
3299e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr
3309e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvrdef Offset(x=0, y=0):
331f184f754862637ad9c3c32952a0756414e2b67a6jvr	"""Return the identity transformation offset by x, y.
332f184f754862637ad9c3c32952a0756414e2b67a6jvr
333f184f754862637ad9c3c32952a0756414e2b67a6jvr	Example:
334f184f754862637ad9c3c32952a0756414e2b67a6jvr		>>> Offset(2, 3)
335f184f754862637ad9c3c32952a0756414e2b67a6jvr		<Transform [1 0 0 1 2 3]>
336f184f754862637ad9c3c32952a0756414e2b67a6jvr		>>>
337f184f754862637ad9c3c32952a0756414e2b67a6jvr	"""
3389e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr	return Transform(1, 0, 0, 1, x, y)
3399e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr
3409e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvrdef Scale(x, y=None):
341f184f754862637ad9c3c32952a0756414e2b67a6jvr	"""Return the identity transformation scaled by x, y. The 'y' argument
342f184f754862637ad9c3c32952a0756414e2b67a6jvr	may be None, which implies to use the x value for y as well.
343f184f754862637ad9c3c32952a0756414e2b67a6jvr
344f184f754862637ad9c3c32952a0756414e2b67a6jvr	Example:
345f184f754862637ad9c3c32952a0756414e2b67a6jvr		>>> Scale(2, 3)
346f184f754862637ad9c3c32952a0756414e2b67a6jvr		<Transform [2 0 0 3 0 0]>
347f184f754862637ad9c3c32952a0756414e2b67a6jvr		>>>
348f184f754862637ad9c3c32952a0756414e2b67a6jvr	"""
3499e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr	if y is None:
3509e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr		y = x
3519e58c90401ef3ce7ed4a85fbda14bbbc564ebf0ejvr	return Transform(x, 0, 0, y, 0, 0)
352f184f754862637ad9c3c32952a0756414e2b67a6jvr
353f184f754862637ad9c3c32952a0756414e2b67a6jvr
354f184f754862637ad9c3c32952a0756414e2b67a6jvrif __name__ == "__main__":
355153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod	import doctest
356153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod	doctest.testmod()
357