1'''functions for 2D affine transformations''' 2__all__ = ( 3 'nullTransform', 4 'translate', 5 'scale', 6 'rotate', 7 'skewX', 8 'skewY', 9 'mmult', 10 'inverse', 11 'zTransformPoint', 12 'transformPoint', 13 'transformPoints', 14 'zTransformPoints', 15 ) 16from math import pi, cos, sin, tan 17 18# constructors for matrices: 19def nullTransform(): 20 return (1, 0, 0, 1, 0, 0) 21 22def translate(dx, dy): 23 return (1, 0, 0, 1, dx, dy) 24 25def scale(sx, sy): 26 return (sx, 0, 0, sy, 0, 0) 27 28def rotate(angle): 29 a = angle * pi/180 30 return (cos(a), sin(a), -sin(a), cos(a), 0, 0) 31 32def skewX(angle): 33 a = angle * pi/180 34 return (1, 0, tan(a), 1, 0, 0) 35 36def skewY(angle): 37 a = angle * pi/180 38 return (1, tan(a), 0, 1, 0, 0) 39 40def mmult(A, B): 41 "A postmultiplied by B" 42 # I checked this RGB 43 # [a0 a2 a4] [b0 b2 b4] 44 # [a1 a3 a5] * [b1 b3 b5] 45 # [ 1 ] [ 1 ] 46 # 47 return (A[0]*B[0] + A[2]*B[1], 48 A[1]*B[0] + A[3]*B[1], 49 A[0]*B[2] + A[2]*B[3], 50 A[1]*B[2] + A[3]*B[3], 51 A[0]*B[4] + A[2]*B[5] + A[4], 52 A[1]*B[4] + A[3]*B[5] + A[5]) 53 54def inverse(A): 55 "For A affine 2D represented as 6vec return 6vec version of A**(-1)" 56 # I checked this RGB 57 det = float(A[0]*A[3] - A[2]*A[1]) 58 R = [A[3]/det, -A[1]/det, -A[2]/det, A[0]/det] 59 return tuple(R+[-R[0]*A[4]-R[2]*A[5],-R[1]*A[4]-R[3]*A[5]]) 60 61def zTransformPoint(A,v): 62 "Apply the homogenous part of atransformation a to vector v --> A*v" 63 return (A[0]*v[0]+A[2]*v[1],A[1]*v[0]+A[3]*v[1]) 64 65def transformPoint(A,v): 66 "Apply transformation a to vector v --> A*v" 67 return (A[0]*v[0]+A[2]*v[1]+A[4],A[1]*v[0]+A[3]*v[1]+A[5]) 68 69def transformPoints(matrix, V): 70 r = [transformPoint(matrix,v) for v in V] 71 if isinstance(V,tuple): r = tuple(r) 72 return r 73 74def zTransformPoints(matrix, V): 75 return list(map(lambda x,matrix=matrix: zTransformPoint(matrix,x), V)) 76