File indexing completed on 2025-01-19 03:59:55
0001 import math 0002 from ..nvector import NVector 0003 0004 0005 def _sign(x): 0006 if x < 0: 0007 return -1 0008 return 1 0009 0010 0011 class TransformMatrix: 0012 scalar = float 0013 0014 def __init__(self): 0015 """ Creates an Identity matrix """ 0016 self.to_identity() 0017 0018 def clone(self): 0019 m = TransformMatrix() 0020 m._mat = list(self._mat) 0021 return m 0022 0023 return self 0024 0025 def __getitem__(self, key): 0026 row, col = key 0027 return self._mat[row*4+col] 0028 0029 def __setitem__(self, key, value): 0030 row, col = key 0031 self._mat[row*4+col] = self.scalar(value) 0032 0033 @property 0034 def a(self): 0035 return self[0, 0] 0036 0037 @a.setter 0038 def a(self, v): 0039 self[0, 0] = self.scalar(v) 0040 0041 @property 0042 def b(self): 0043 return self[0, 1] 0044 0045 @b.setter 0046 def b(self, v): 0047 self[0, 1] = self.scalar(v) 0048 0049 @property 0050 def c(self): 0051 return self[1, 0] 0052 0053 @c.setter 0054 def c(self, v): 0055 self[1, 0] = self.scalar(v) 0056 0057 @property 0058 def d(self): 0059 return self[1, 1] 0060 0061 @d.setter 0062 def d(self, v): 0063 self[1, 1] = self.scalar(v) 0064 0065 @property 0066 def tx(self): 0067 return self[3, 0] 0068 0069 @tx.setter 0070 def tx(self, v): 0071 self[3, 0] = self.scalar(v) 0072 0073 @property 0074 def ty(self): 0075 return self[3, 1] 0076 0077 @ty.setter 0078 def ty(self, v): 0079 self[3, 1] = self.scalar(v) 0080 0081 def __str__(self): 0082 return str(self._mat) 0083 0084 def scale(self, x, y=None): 0085 if y is None: 0086 y = x 0087 0088 m = TransformMatrix() 0089 m.a = x 0090 m.d = y 0091 self *= m 0092 return self 0093 0094 def translate(self, x, y=None): 0095 if y is None: 0096 x, y = x 0097 m = TransformMatrix() 0098 m.tx = x 0099 m.ty = y 0100 self *= m 0101 return self 0102 0103 def skew(self, x_rad, y_rad): 0104 m = TransformMatrix() 0105 m.c = math.tan(x_rad) 0106 m.b = math.tan(y_rad) 0107 self *= m 0108 return self 0109 0110 def skew_from_axis(self, skew, axis): 0111 self.rotate(axis) 0112 m = TransformMatrix() 0113 m.c = math.tan(skew) 0114 self *= m 0115 self.rotate(-axis) 0116 return self 0117 0118 def row(self, i): 0119 return NVector(self[i, 0], self[i, 1], self[i, 2], self[i, 3]) 0120 0121 def column(self, i): 0122 return NVector(self[0, i], self[1, i], self[2, i], self[3, i]) 0123 0124 def to_identity(self): 0125 self._mat = [ 0126 1., 0., 0., 0., 0127 0., 1., 0., 0., 0128 0., 0., 1., 0., 0129 0., 0., 0., 1., 0130 ] 0131 0132 def apply(self, vector): 0133 vector3 = NVector(vector.x, vector.y, 0, 1) 0134 return NVector( 0135 self.column(0).dot(vector3), 0136 self.column(1).dot(vector3), 0137 ) 0138 0139 @classmethod 0140 def rotation(cls, radians): 0141 m = cls() 0142 m.a = math.cos(radians) 0143 m.b = -math.sin(radians) 0144 m.c = math.sin(radians) 0145 m.d = math.cos(radians) 0146 0147 return m 0148 0149 def __mul__(self, other): 0150 m = TransformMatrix() 0151 for row in range(4): 0152 for col in range(4): 0153 m[row, col] = self.row(row).dot(other.column(col)) 0154 return m 0155 0156 def __imul__(self, other): 0157 m = self * other 0158 self._mat = m._mat 0159 return self 0160 0161 def rotate(self, radians): 0162 self *= TransformMatrix.rotation(radians) 0163 return self 0164 0165 def extract_transform(self): 0166 a = self.a 0167 b = self.b 0168 c = self.c 0169 d = self.d 0170 tx = self.tx 0171 ty = self.ty 0172 0173 dest_trans = { 0174 "translation": NVector(tx, ty), 0175 "angle": 0, 0176 "scale": NVector(1, 1), 0177 "skew_axis": 0, 0178 "skew_angle": 0, 0179 } 0180 0181 delta = a * d - b * c 0182 if a != 0 or b != 0: 0183 r = math.hypot(a, b) 0184 dest_trans["angle"] = - _sign(b) * math.acos(a/r) 0185 sx = r 0186 sy = delta / r 0187 dest_trans["skew_axis"] = 0 0188 else: 0189 r = math.hypot(c, d) 0190 dest_trans["angle"] = math.pi / 2 + _sign(d) * math.acos(c / r) 0191 sx = delta / r 0192 sy = r 0193 dest_trans["skew_axis"] = math.pi / 2 0194 0195 dest_trans["scale"] = NVector(sx, sy) 0196 0197 skew = math.atan2((a * c + b * d), r * r) 0198 dest_trans["skew_angle"] = skew 0199 0200 return dest_trans 0201 0202 def to_css_2d(self): 0203 return "matrix(%s, %s, %s, %s, %s, %s)" % ( 0204 self.a, self.b, self.c, self.d, self.tx, self.ty 0205 )