@@ -2,33 +2,66 @@ local module = {}
22playdate .geometry .affineTransform = module
33
44local meta = {}
5-
65meta .__index = meta
6+ module .__index = meta
77
8- meta .__mul = function (a , b )
9- error (" [ERR] playdate.geometry.affineTransform.__mul is not yet implemented." )
8+ local function concat (a , b )
9+ return
10+ a .m11 * b .m11 + a .m21 * b .m12 ,
11+ a .m12 * b .m11 + a .m22 * b .m12 ,
12+ a .m11 * b .m21 + a .m21 * b .m22 ,
13+ a .m12 * b .m21 + a .m22 * b .m22 ,
14+ a .tx * b .m11 + a .ty * b .m12 + b .tx ,
15+ a .tx * b .m21 + a .ty * b .m22 + b .ty
1016end
1117
12- module .__index = meta
18+
19+ local function transform (t , x , y )
20+ return
21+ x * t .m11 + y * t .m12 + t .tx ,
22+ x * t .m21 + y * t .m22 + t .ty
23+ end
24+
25+ local function translation (dx , dy )
26+ return module .new (1 , 0 , 0 , 1 , dx , dy )
27+ end
28+
29+ local function scaling (sx , sy )
30+ sy = sy or sx
31+ return module .new (sx , 0 , 0 , sy , 0 , 0 )
32+ end
33+
34+ local function rotation (angle )
35+ angle = math.rad (angle )
36+ local c = math.cos (angle )
37+ local s = math.sin (angle )
38+ return module .new (c , - s , s , c , 0 , 0 )
39+ end
40+
41+ local function rotationAround (angle , px , py )
42+ local rad = math.rad (angle )
43+ local c = math.cos (rad )
44+ local s = math.sin (rad )
45+ local tx = px - px * c + py * s
46+ local ty = py - px * s - py * c
47+ return module .new (c , - s , s , c , tx , ty )
48+ end
49+
50+ local function skewing (sx , sy )
51+ local rx = math.tan (math.rad (sx ))
52+ local ry = math.tan (math.rad (sy ))
53+ return module .new (1 , rx , ry , 1 , 0 , 0 )
54+ end
1355
1456function module .new (m11 , m12 , m21 , m22 , tx , ty )
1557 local o = {}
1658
17- if m11 then
18- o .m11 = m11
19- o .m12 = m12
20- o .m21 = m21
21- o .m22 = m22
22- o .tx = tx
23- o .ty = ty
24- else
25- o .m11 = 1
26- o .m12 = 0
27- o .m21 = 0
28- o .m22 = 1
29- o .tx = 0
30- o .ty = 0
31- end
59+ o .m11 = m11 or 1
60+ o .m12 = m12 or 0
61+ o .m21 = m21 or 0
62+ o .m22 = m22 or 1
63+ o .tx = tx or 0
64+ o .ty = ty or 0
3265
3366 setmetatable (o , meta )
3467 return o
@@ -43,7 +76,27 @@ function meta:unpack()
4376end
4477
4578function meta :invert ()
46- error (" [ERR] playdate.geometry.affineTransform:invert() is not yet implemented." )
79+ local a , b = self .m11 , self .m12
80+ local c , d = self .m21 , self .m22
81+ local tx , ty = self .tx , self .ty
82+
83+ local det = a * d - b * c
84+ local invDet = 1 / det
85+
86+ local im11 = d * invDet
87+ local im12 = - b * invDet
88+ local im21 = - c * invDet
89+ local im22 = a * invDet
90+
91+ local itx = - (im11 * tx + im12 * ty )
92+ local ity = - (im21 * tx + im22 * ty )
93+
94+ self .m11 = im11
95+ self .m12 = im12
96+ self .m21 = im21
97+ self .m22 = im22
98+ self .tx = itx
99+ self .ty = ity
47100end
48101
49102function meta :reset ()
@@ -55,88 +108,131 @@ function meta:reset()
55108 self .ty = 0
56109end
57110
58- function meta :concat (af )
59- local m11 = self .m11 * af .m11 + self .m12 * af .m21
60- local m12 = self .m11 * af .m12 + self .m12 * af .m22
61-
62- local m21 = self .m21 * af .m11 + self .m22 * af .m21
63- local m22 = self .m21 * af .m12 + self .m22 * af .m22
64-
65- local tx = self .m11 * af .tx + self .m12 * af .ty + self .tx
66- local ty = self .m21 * af .tx + self .m22 * af .ty + self .ty
67-
68- return module .new (m11 , m12 , m21 , m22 , tx , ty )
111+ function meta :concat (b )
112+ self .m11 , self .m12 , self .m21 , self .m22 , self .tx , self .ty = concat (self , b )
69113end
70114
71115function meta :translate (dx , dy )
72- error (" [ERR] playdate.geometry.affineTransform:translate() is not yet implemented." )
116+ local t = translation (dx , dy )
117+ self :concat (t )
73118end
74119
75120function meta :translatedBy (dx , dy )
76- error (" [ERR] playdate.geometry.affineTransform:translatedBy() is not yet implemented." )
121+ local t = self :copy ()
122+ t :translate (dx , dy )
123+ return t
77124end
78125
79126function meta :scale (sx , sy )
80- error (" [ERR] playdate.geometry.affineTransform:scale() is not yet implemented." )
127+ local t = scaling (sx , sy )
128+ self :concat (t )
81129end
82130
83131function meta :scaledBy (sx , sy )
84- error (" [ERR] playdate.geometry.affineTransform:scaledBy() is not yet implemented." )
132+ local t = self :copy ()
133+ t :scale (sx , sy )
134+ return t
85135end
86136
87- function meta :rotate (angle , pointOrX , y )
88- error (" [ERR] playdate.geometry.affineTransform:rotate() is not yet implemented." )
137+ function meta :rotate (angle , x , y )
138+ local t
139+
140+ if x then
141+ if y then
142+ t = rotationAround (angle , x , y )
143+ else
144+ local pt = x
145+ t = rotationAround (angle , pt .x , pt .y )
146+ end
147+ else
148+ t = rotation (angle )
149+ end
150+
151+ self :concat (t )
89152end
90153
91- function meta :rotateBy (angle , pointOrX , y )
92- error (" [ERR] playdate.geometry.affineTransform:rotateBy() is not yet implemented." )
154+ function meta :rotatedBy (angle , pointOrX , y )
155+ local t = self :copy ()
156+ t :rotate (angle , pointOrX , y )
157+ return t
93158end
94159
95160function meta :skew (sx , sy )
96- error (" [ERR] playdate.geometry.affineTransform:skew() is not yet implemented." )
161+ local t = skewing (sx , sy )
162+ self :concat (t )
97163end
98164
99165function meta :skewedBy (sx , sy )
100- error (" [ERR] playdate.geometry.affineTransform:skewedBy() is not yet implemented." )
166+ local t = self :copy ()
167+ t :skew (sx , sy )
168+ return t
101169end
102170
103- function meta :transformPoint (p )
104- local nx , ny = self :transformXY (p .x , p .y )
105- p .x = nx
106- p .y = ny
171+ function meta :transformXY (x , y )
172+ return transform (self , x , y )
107173end
108174
109- function meta :transformedPoint (p )
110- local nx , ny = self :transformXY (p .x , p .y )
111- return playdate .geometry .point .new (nx , ny )
175+ function meta :transformPoint (p )
176+ p .x , p .y = transform (self , p .x , p .y )
112177end
113178
114- function meta :transformXY ( x , y )
115- local nx = x * self . m11 + y * self . m12 + self . tx
116- local ny = x * self . m21 + y * self . m22 + self . ty
117- return nx , ny
179+ function meta :transformedPoint ( p )
180+ local c = p : copy ()
181+ self : transformPoint ( c )
182+ return c
118183end
119184
120185function meta :transformLineSegment (ls )
121- error (" [ERR] playdate.geometry.affineTransform:transformLineSegment() is not yet implemented." )
186+ ls .x1 , ls .y1 = transform (self , ls .x1 , ls .y1 )
187+ ls .x2 , ls .y2 = transform (self , ls .x2 , ls .y2 )
122188end
123189
124190function meta :transformedLineSegment (ls )
125- error (" [ERR] playdate.geometry.affineTransform:transformedLineSegment() is not yet implemented." )
191+ local c = ls :copy ()
192+ self :transformLineSegment (c )
193+ return c
126194end
127195
128196function meta :transformAABB (r )
129197 error (" [ERR] playdate.geometry.affineTransform:transformAABB() is not yet implemented." )
130198end
131199
132200function meta :transformedAABB (r )
133- error (" [ERR] playdate.geometry.affineTransform:transformedAABB() is not yet implemented." )
201+ local c = r :copy ()
202+ self :transformAABB (c )
203+ return c
134204end
135205
136206function meta :transformPolygon (p )
137- error (" [ERR] playdate.geometry.affineTransform:transformPolygon() is not yet implemented." )
207+ local pts = p ._points
208+ for i = 1 , # pts , 2 do
209+ local j = i + 1
210+ pts [i ], pts [j ] = transform (self , pts [i ], pts [j ])
211+ end
138212end
139213
140214function meta :transformedPolygon (p )
141- error (" [ERR] playdate.geometry.affineTransform:transformedPolygon() is not yet implemented." )
215+ local c = p :copy ()
216+ self :transformPolygon (c )
217+ return c
142218end
219+
220+ meta .__mul = function (a , b )
221+ if b ._type == " point" then
222+ local x , y = transform (a , b .x , b .y )
223+ return playdate .geometry .point .new (x , y )
224+
225+ elseif b ._type == " vector2D" then
226+ local dx , dy = transform (a , b .dx , b .dy )
227+ return playdate .geometry .vector2D .new (dx , dy )
228+
229+ else
230+ local m11 , m12 , m21 , m22 , tx , ty = concat (a , b )
231+ return module .new (m11 , m12 , m21 , m22 , tx , ty )
232+ end
233+ end
234+
235+ meta .__tostring = function (t )
236+ return string.format (" (m11=%s, m12=%s, m21=%s, m22=%s, tx=%s, ty=%s)" ,
237+ t .m11 , t .m12 , t .m21 , t .m22 , t .tx , t .ty )
238+ end
0 commit comments