Coverage for lib/lottie/utils/transform.py: 90%
131 statements
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-20 16:17 +0100
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-20 16:17 +0100
1import math
2from ..nvector import NVector
5def _sign(x):
6 if x < 0:
7 return -1
8 return 1
11class TransformMatrix:
12 scalar = float
14 def __init__(self):
15 """ Creates an Identity matrix """
16 self.to_identity()
18 def clone(self):
19 m = TransformMatrix()
20 m._mat = list(self._mat)
21 return m
23 return self
25 def __getitem__(self, key):
26 row, col = key
27 return self._mat[row*4+col]
29 def __setitem__(self, key, value):
30 row, col = key
31 self._mat[row*4+col] = self.scalar(value)
33 @property
34 def a(self):
35 return self[0, 0]
37 @a.setter
38 def a(self, v):
39 self[0, 0] = self.scalar(v)
41 @property
42 def b(self):
43 return self[0, 1]
45 @b.setter
46 def b(self, v):
47 self[0, 1] = self.scalar(v)
49 @property
50 def c(self):
51 return self[1, 0]
53 @c.setter
54 def c(self, v):
55 self[1, 0] = self.scalar(v)
57 @property
58 def d(self):
59 return self[1, 1]
61 @d.setter
62 def d(self, v):
63 self[1, 1] = self.scalar(v)
65 @property
66 def tx(self):
67 return self[3, 0]
69 @tx.setter
70 def tx(self, v):
71 self[3, 0] = self.scalar(v)
73 @property
74 def ty(self):
75 return self[3, 1]
77 @ty.setter
78 def ty(self, v):
79 self[3, 1] = self.scalar(v)
81 def __str__(self):
82 return str(self._mat)
84 def scale(self, x, y=None):
85 if y is None:
86 y = x
88 m = TransformMatrix()
89 m.a = x
90 m.d = y
91 self *= m
92 return self
94 def translate(self, x, y=None):
95 if y is None: 95 ↛ 96line 95 didn't jump to line 96, because the condition on line 95 was never true
96 x, y = x
97 m = TransformMatrix()
98 m.tx = x
99 m.ty = y
100 self *= m
101 return self
103 def skew(self, x_rad, y_rad):
104 m = TransformMatrix()
105 m.c = math.tan(x_rad)
106 m.b = math.tan(y_rad)
107 self *= m
108 return self
110 def skew_from_axis(self, skew, axis):
111 self.rotate(axis)
112 m = TransformMatrix()
113 m.c = math.tan(skew)
114 self *= m
115 self.rotate(-axis)
116 return self
118 def row(self, i):
119 return NVector(self[i, 0], self[i, 1], self[i, 2], self[i, 3])
121 def column(self, i):
122 return NVector(self[0, i], self[1, i], self[2, i], self[3, i])
124 def to_identity(self):
125 self._mat = [
126 1., 0., 0., 0.,
127 0., 1., 0., 0.,
128 0., 0., 1., 0.,
129 0., 0., 0., 1.,
130 ]
132 def apply(self, vector):
133 vector3 = NVector(vector.x, vector.y, 0, 1)
134 return NVector(
135 self.column(0).dot(vector3),
136 self.column(1).dot(vector3),
137 )
139 @classmethod
140 def rotation(cls, radians):
141 m = cls()
142 m.a = math.cos(radians)
143 m.b = -math.sin(radians)
144 m.c = math.sin(radians)
145 m.d = math.cos(radians)
147 return m
149 def __mul__(self, other):
150 m = TransformMatrix()
151 for row in range(4):
152 for col in range(4):
153 m[row, col] = self.row(row).dot(other.column(col))
154 return m
156 def __imul__(self, other):
157 m = self * other
158 self._mat = m._mat
159 return self
161 def rotate(self, radians):
162 self *= TransformMatrix.rotation(radians)
163 return self
165 def extract_transform(self):
166 a = self.a
167 b = self.b
168 c = self.c
169 d = self.d
170 tx = self.tx
171 ty = self.ty
173 dest_trans = {
174 "translation": NVector(tx, ty),
175 "angle": 0,
176 "scale": NVector(1, 1),
177 "skew_axis": 0,
178 "skew_angle": 0,
179 }
181 delta = a * d - b * c
182 if a != 0 or b != 0: 182 ↛ 189line 182 didn't jump to line 189, because the condition on line 182 was never false
183 r = math.hypot(a, b)
184 dest_trans["angle"] = - _sign(b) * math.acos(a/r)
185 sx = r
186 sy = delta / r
187 dest_trans["skew_axis"] = 0
188 else:
189 r = math.hypot(c, d)
190 dest_trans["angle"] = math.pi / 2 + _sign(d) * math.acos(c / r)
191 sx = delta / r
192 sy = r
193 dest_trans["skew_axis"] = math.pi / 2
195 dest_trans["scale"] = NVector(sx, sy)
197 skew = math.atan2((a * c + b * d), r * r)
198 dest_trans["skew_angle"] = skew
200 return dest_trans
202 def to_css_2d(self):
203 return "matrix(%s, %s, %s, %s, %s, %s)" % (
204 self.a, self.b, self.c, self.d, self.tx, self.ty
205 )