From c0d100f7e80c73a5f23331c969520dea61e86677 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 3 Feb 2023 10:06:47 -0700 Subject: [PATCH] [transform] Add DecomposedTransform.fromTransform() --- Lib/fontTools/misc/transform.py | 74 +++++++++++++++++---------------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/Lib/fontTools/misc/transform.py b/Lib/fontTools/misc/transform.py index 101652969..786df84b4 100644 --- a/Lib/fontTools/misc/transform.py +++ b/Lib/fontTools/misc/transform.py @@ -351,41 +351,7 @@ class Transform(NamedTuple): def toDecomposed(self) -> "DecomposedTransform": """Decompose into a DecomposedTransform.""" - # Adapted from an answer on - # https://math.stackexchange.com/questions/13150/extracting-rotation-scale-values-from-2d-transformation-matrix - a, b, c, d, x, y = self - delta = a * d - b * c - - rotation = 0 - scaleX = scaleY = 0 - skewX = skewY = 0 - - # Apply the QR-like decomposition. - if a != 0 or b != 0: - r = math.sqrt(a * a + b * b) - rotation = math.acos(a / r) if b > 0 else -math.acos(a / r) - scaleX, scaleY = (r, delta / r) - skewX, skewY = (math.atan((a * c + b * d) / (r * r)), 0) - elif c != 0 or d != 0: - s = math.sqrt(c * c + d * d) - rotation = math.pi / 2 - (math.acos(-c / s) if d > 0 else -math.acos(c / s)) - scaleX, scaleY = (delta / s, s) - skewX, skewY = (0, math.atan((a * c + b * d) / (s * s))) - else: - # a = b = c = d = 0 - pass - - return DecomposedTransform( - x, - y, - math.degrees(rotation), - scaleX, - scaleY, - -math.degrees(skewX), - math.degrees(skewY), - 0, - 0, - ) + return DecomposedTransform.fromTransform(self) def __bool__(self): """Returns True if transform is not identity, False otherwise. @@ -457,6 +423,44 @@ class DecomposedTransform: tCenterX: float = 0 tCenterY: float = 0 + @classmethod + def fromTransform(self, transform): + # Adapted from an answer on + # https://math.stackexchange.com/questions/13150/extracting-rotation-scale-values-from-2d-transformation-matrix + a, b, c, d, x, y = transform + delta = a * d - b * c + + rotation = 0 + scaleX = scaleY = 0 + skewX = skewY = 0 + + # Apply the QR-like decomposition. + if a != 0 or b != 0: + r = math.sqrt(a * a + b * b) + rotation = math.acos(a / r) if b > 0 else -math.acos(a / r) + scaleX, scaleY = (r, delta / r) + skewX, skewY = (math.atan((a * c + b * d) / (r * r)), 0) + elif c != 0 or d != 0: + s = math.sqrt(c * c + d * d) + rotation = math.pi / 2 - (math.acos(-c / s) if d > 0 else -math.acos(c / s)) + scaleX, scaleY = (delta / s, s) + skewX, skewY = (0, math.atan((a * c + b * d) / (s * s))) + else: + # a = b = c = d = 0 + pass + + return DecomposedTransform( + x, + y, + math.degrees(rotation), + scaleX, + scaleY, + -math.degrees(skewX), + math.degrees(skewY), + 0, + 0, + ) + def toTransform(self): """Return the Transform() equivalent of this transformation.