pyembroidery/pyembroidery/EmbMatrix.py

161 wiersze
5.0 KiB
Python

import math
class EmbMatrix:
def __init__(self, m=None):
if m is None:
self.m = self.get_identity()
else:
self.m = m
def __ne__(self, other):
return not self.__eq__(other)
def __eq__(self, other):
return self.m == other.m
def __matmul__(self, other):
return EmbMatrix(EmbMatrix.matrix_multiply(self.m, other.m))
def __rmatmul__(self, other):
return EmbMatrix(EmbMatrix.matrix_multiply(self.m, other.m))
def __imatmul__(self, other):
self.m = EmbMatrix.matrix_multiply(self.m, other.m)
def __str__(self):
return "[%3f, %3f, %3f\n %3f, %3f, %3f\n %3f, %3f, %3f]" % self.m
def get_matrix(self):
return self.m
def reset(self):
self.m = self.get_identity()
def inverse(self):
m = self.m
m48s75 = m[4] * m[8] - m[7] * m[5]
m38s56 = m[5] * m[6] - m[3] * m[8]
m37s46 = m[3] * m[7] - m[4] * m[6]
det = m[0] * m48s75 + m[1] * m38s56 + m[2] * m37s46
inverse_det = 1.0 / float(det)
self.m = [
m48s75 * inverse_det,
(m[2] * m[7] - m[1] * m[8]) * inverse_det,
(m[1] * m[5] - m[2] * m[4]) * inverse_det,
m38s56 * inverse_det,
(m[0] * m[8] - m[2] * m[6]) * inverse_det,
(m[3] * m[2] - m[0] * m[5]) * inverse_det,
m37s46 * inverse_det,
(m[6] * m[1] - m[0] * m[7]) * inverse_det,
(m[0] * m[4] - m[3] * m[1]) * inverse_det,
]
def post_scale(self, sx=1, sy=None, x=0, y=0):
if sy is None:
sy = sx
if x is None:
x = 0
if y is None:
y = 0
if x == 0 and y == 0:
self.m = self.matrix_multiply(self.m, self.get_scale(sx, sy))
else:
self.post_translate(x, y)
self.post_scale(sx, sy)
self.post_translate(-x, -y)
def post_translate(self, tx, ty):
self.m = self.matrix_multiply(self.m, self.get_translate(tx, ty))
def post_rotate(self, theta, x=0, y=0):
if x is None:
x = 0
if y is None:
y = 0
if x == 0 and y == 0:
self.m = self.matrix_multiply(self.m, self.get_rotate(theta))
else:
self.post_translate(x, y)
self.post_rotate(theta)
self.post_translate(-x, -y)
def post_cat(self, matrix_list):
for mx in matrix_list:
self.m = self.matrix_multiply(self.m, mx)
def pre_scale(self, sx=1, sy=None):
if sy is None:
sy = sx
self.m = self.matrix_multiply(self.get_scale(sx, sy), self.m)
def pre_translate(self, tx, ty):
self.m = self.matrix_multiply(self.get_translate(tx, ty), self.m)
def pre_rotate(self, theta):
self.m = self.matrix_multiply(self.get_rotate(theta), self.m)
def pre_cat(self, matrix_list):
for mx in matrix_list:
self.m = self.matrix_multiply(mx, self.m)
def point_in_matrix_space(self, v0, v1=None):
m = self.m
if v1 is None:
try:
return [
v0[0] * m[0] + v0[1] * m[3] + 1 * m[6],
v0[0] * m[1] + v0[1] * m[4] + 1 * m[7],
v0[2],
]
except IndexError:
return [
v0[0] * m[0] + v0[1] * m[3] + 1 * m[6],
v0[0] * m[1] + v0[1] * m[4] + 1 * m[7]
# Must not have had a 3rd element.
]
return [v0 * m[0] + v1 * m[3] + 1 * m[6], v0 * m[1] + v1 * m[4] + 1 * m[7]]
def apply(self, v):
m = self.m
nx = v[0] * m[0] + v[1] * m[3] + 1 * m[6]
ny = v[0] * m[1] + v[1] * m[4] + 1 * m[7]
v[0] = nx
v[1] = ny
@staticmethod
def get_identity():
return 1, 0, 0, 0, 1, 0, 0, 0, 1 # identity
@staticmethod
def get_scale(sx, sy=None):
if sy is None:
sy = sx
return sx, 0, 0, 0, sy, 0, 0, 0, 1
@staticmethod
def get_translate(tx, ty):
return 1, 0, 0, 0, 1, 0, tx, ty, 1
@staticmethod
def get_rotate(theta):
tau = math.pi * 2
theta *= tau / 360
ct = math.cos(theta)
st = math.sin(theta)
return ct, st, 0, -st, ct, 0, 0, 0, 1
@staticmethod
def matrix_multiply(m0, m1):
return [
m1[0] * m0[0] + m1[1] * m0[3] + m1[2] * m0[6],
m1[0] * m0[1] + m1[1] * m0[4] + m1[2] * m0[7],
m1[0] * m0[2] + m1[1] * m0[5] + m1[2] * m0[8],
m1[3] * m0[0] + m1[4] * m0[3] + m1[5] * m0[6],
m1[3] * m0[1] + m1[4] * m0[4] + m1[5] * m0[7],
m1[3] * m0[2] + m1[4] * m0[5] + m1[5] * m0[8],
m1[6] * m0[0] + m1[7] * m0[3] + m1[8] * m0[6],
m1[6] * m0[1] + m1[7] * m0[4] + m1[8] * m0[7],
m1[6] * m0[2] + m1[7] * m0[5] + m1[8] * m0[8],
]