[transform] Add DecomposedTransform.fromTransform()

This commit is contained in:
Behdad Esfahbod 2023-02-03 10:06:47 -07:00
parent cf9dece8f2
commit c0d100f7e8

View File

@ -351,41 +351,7 @@ class Transform(NamedTuple):
def toDecomposed(self) -> "DecomposedTransform": def toDecomposed(self) -> "DecomposedTransform":
"""Decompose into a DecomposedTransform.""" """Decompose into a DecomposedTransform."""
# Adapted from an answer on return DecomposedTransform.fromTransform(self)
# 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,
)
def __bool__(self): def __bool__(self):
"""Returns True if transform is not identity, False otherwise. """Returns True if transform is not identity, False otherwise.
@ -457,6 +423,44 @@ class DecomposedTransform:
tCenterX: float = 0 tCenterX: float = 0
tCenterY: 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): def toTransform(self):
"""Return the Transform() equivalent of this transformation. """Return the Transform() equivalent of this transformation.