diff options
Diffstat (limited to 'Lib/fontTools/misc/transform.py')
-rw-r--r-- | Lib/fontTools/misc/transform.py | 93 |
1 files changed, 69 insertions, 24 deletions
diff --git a/Lib/fontTools/misc/transform.py b/Lib/fontTools/misc/transform.py index 997598f5..94e1f622 100644 --- a/Lib/fontTools/misc/transform.py +++ b/Lib/fontTools/misc/transform.py @@ -10,12 +10,16 @@ used as dictionary keys. This module exports the following symbols: - Transform -- this is the main class - Identity -- Transform instance set to the identity transformation - Offset -- Convenience function that returns a translating transformation - Scale -- Convenience function that returns a scaling transformation +Transform + this is the main class +Identity + Transform instance set to the identity transformation +Offset + Convenience function that returns a translating transformation +Scale + Convenience function that returns a scaling transformation -Examples: +:Example: >>> t = Transform(2, 0, 0, 3, 0, 0) >>> t.transformPoint((100, 100)) @@ -72,7 +76,8 @@ class Transform(NamedTuple): Transform instances are immutable: all transforming methods, eg. rotate(), return a new Transform instance. - Examples: + :Example: + >>> t = Transform() >>> t <Transform [1 0 0 1 0 0]> @@ -85,7 +90,8 @@ class Transform(NamedTuple): (200, 300) Transform's constructor takes six arguments, all of which are - optional, and can be used as keyword arguments: + optional, and can be used as keyword arguments:: + >>> Transform(12) <Transform [12 0 0 1 0 0]> >>> Transform(dx=12) @@ -93,7 +99,8 @@ class Transform(NamedTuple): >>> Transform(yx=12) <Transform [1 0 12 1 0 0]> - Transform instances also behave like sequences of length 6: + Transform instances also behave like sequences of length 6:: + >>> len(Identity) 6 >>> list(Identity) @@ -101,13 +108,15 @@ class Transform(NamedTuple): >>> tuple(Identity) (1, 0, 0, 1, 0, 0) - Transform instances are comparable: + Transform instances are comparable:: + >>> t1 = Identity.scale(2, 3).translate(4, 6) >>> t2 = Identity.translate(8, 18).scale(2, 3) >>> t1 == t2 1 - But beware of floating point rounding errors: + But beware of floating point rounding errors:: + >>> t1 = Identity.scale(0.2, 0.3).translate(0.4, 0.6) >>> t2 = Identity.translate(0.08, 0.18).scale(0.2, 0.3) >>> t1 @@ -118,12 +127,14 @@ class Transform(NamedTuple): 0 Transform instances are hashable, meaning you can use them as - keys in dictionaries: + keys in dictionaries:: + >>> d = {Scale(12, 13): None} >>> d {<Transform [12 0 0 13 0 0]>: None} - But again, beware of floating point rounding errors: + But again, beware of floating point rounding errors:: + >>> t1 = Identity.scale(0.2, 0.3).translate(0.4, 0.6) >>> t2 = Identity.translate(0.08, 0.18).scale(0.2, 0.3) >>> t1 @@ -149,7 +160,8 @@ class Transform(NamedTuple): def transformPoint(self, p): """Transform a point. - Example: + :Example: + >>> t = Transform() >>> t = t.scale(2.5, 5.5) >>> t.transformPoint((100, 100)) @@ -162,7 +174,8 @@ class Transform(NamedTuple): def transformPoints(self, points): """Transform a list of points. - Example: + :Example: + >>> t = Scale(2, 3) >>> t.transformPoints([(0, 0), (0, 100), (100, 100), (100, 0)]) [(0, 0), (0, 300), (200, 300), (200, 0)] @@ -171,10 +184,36 @@ class Transform(NamedTuple): xx, xy, yx, yy, dx, dy = self return [(xx*x + yx*y + dx, xy*x + yy*y + dy) for x, y in points] + def transformVector(self, v): + """Transform an (dx, dy) vector, treating translation as zero. + + :Example: + + >>> t = Transform(2, 0, 0, 2, 10, 20) + >>> t.transformVector((3, -4)) + (6, -8) + >>> + """ + (dx, dy) = v + xx, xy, yx, yy = self[:4] + return (xx*dx + yx*dy, xy*dx + yy*dy) + + def transformVectors(self, vectors): + """Transform a list of (dx, dy) vector, treating translation as zero. + + :Example: + >>> t = Transform(2, 0, 0, 2, 10, 20) + >>> t.transformVectors([(3, -4), (5, -6)]) + [(6, -8), (10, -12)] + >>> + """ + xx, xy, yx, yy = self[:4] + return [(xx*dx + yx*dy, xy*dx + yy*dy) for dx, dy in vectors] + def translate(self, x=0, y=0): """Return a new transformation, translated (offset) by x, y. - Example: + :Example: >>> t = Transform() >>> t.translate(20, 30) <Transform [1 0 0 1 20 30]> @@ -186,7 +225,7 @@ class Transform(NamedTuple): """Return a new transformation, scaled by x, y. The 'y' argument may be None, which implies to use the x value for y as well. - Example: + :Example: >>> t = Transform() >>> t.scale(5) <Transform [5 0 0 5 0 0]> @@ -201,7 +240,7 @@ class Transform(NamedTuple): def rotate(self, angle): """Return a new transformation, rotated by 'angle' (radians). - Example: + :Example: >>> import math >>> t = Transform() >>> t.rotate(math.pi / 2) @@ -216,7 +255,7 @@ class Transform(NamedTuple): def skew(self, x=0, y=0): """Return a new transformation, skewed by x and y. - Example: + :Example: >>> import math >>> t = Transform() >>> t.skew(math.pi / 4) @@ -230,7 +269,7 @@ class Transform(NamedTuple): """Return a new transformation, transformed by another transformation. - Example: + :Example: >>> t = Transform(2, 0, 0, 3, 1, 6) >>> t.transform((4, 3, 2, 1, 5, 6)) <Transform [8 9 4 3 11 24]> @@ -251,7 +290,7 @@ class Transform(NamedTuple): transformed by self. self.reverseTransform(other) is equivalent to other.transform(self). - Example: + :Example: >>> t = Transform(2, 0, 0, 3, 1, 6) >>> t.reverseTransform((4, 3, 2, 1, 5, 6)) <Transform [8 6 6 3 21 15]> @@ -272,7 +311,7 @@ class Transform(NamedTuple): def inverse(self): """Return the inverse transformation. - Example: + :Example: >>> t = Identity.translate(2, 3).scale(4, 5) >>> t.transformPoint((10, 20)) (42, 103) @@ -290,7 +329,10 @@ class Transform(NamedTuple): return self.__class__(xx, xy, yx, yy, dx, dy) def toPS(self): - """Return a PostScript representation: + """Return a PostScript representation + + :Example: + >>> t = Identity.scale(2, 3).translate(4, 5) >>> t.toPS() '[2 0 0 3 8 15]' @@ -300,6 +342,9 @@ class Transform(NamedTuple): def __bool__(self): """Returns True if transform is not identity, False otherwise. + + :Example: + >>> bool(Identity) False >>> bool(Transform()) @@ -326,7 +371,7 @@ Identity = Transform() def Offset(x=0, y=0): """Return the identity transformation offset by x, y. - Example: + :Example: >>> Offset(2, 3) <Transform [1 0 0 1 2 3]> >>> @@ -337,7 +382,7 @@ def Scale(x, y=None): """Return the identity transformation scaled by x, y. The 'y' argument may be None, which implies to use the x value for y as well. - Example: + :Example: >>> Scale(2, 3) <Transform [2 0 0 3 0 0]> >>> |