SHOW:
|
|
- or go back to the newest paste.
1 | package ASUtil.Math | |
2 | { | |
3 | import flash.geom.Matrix; | |
4 | import flash.geom.Matrix3D; | |
5 | ||
6 | - | public class matrix extends Object |
6 | + | public final class matrix extends Object |
7 | { | |
8 | ||
9 | public static const opMul:String = "Multiplication"; | |
10 | public static const opAdd:String = "Addition"; | |
11 | public static const opSub:String = "Subtract"; | |
12 | public static const opInv:String = "Inverse"; | |
13 | public static const opFMX:String = "ToFlashMatrix"; | |
14 | public static const opFM3:String = "ToFlashMatrix3D"; | |
15 | ||
16 | private var data:Vector.<Number>; | |
17 | private var W:uint; | |
18 | private var H:uint; | |
19 | ||
20 | public var newLine:Boolean = true; | |
21 | ||
22 | //Constructor. Takes in width, height, and an array of data. You do not have to fill the matrix early, but you can't over-flow it. | |
23 | public function matrix ( width:uint, height:uint, ... dat ) | |
24 | { | |
25 | ||
26 | data = new Vector.<Number> ( width * height, true ); | |
27 | ||
28 | W = width; | |
29 | H = height; | |
30 | ||
31 | if ( dat.length > W * H ) | |
32 | throw new Error ( "More data provided than fits in matrix.", 0 ); | |
33 | ||
34 | for ( var n:uint = 0; n < dat.length; n ++ ) | |
35 | data [ n ] = dat [ n ]; | |
36 | ||
37 | }; | |
38 | ||
39 | //Set a specific element to a value, in X-Y form, top left being the origin, going down and to the right. | |
40 | public function setElement ( x:uint, y:uint, value:Number ) : void | |
41 | { | |
42 | ||
43 | if ( x >= W || y >= H ) | |
44 | throw new Error ( "The coordinance ( " + x + ", " + y + " ) is out of the matrix bounds.", 1 ); | |
45 | ||
46 | data [ x + y * W ] = value; | |
47 | ||
48 | }; | |
49 | ||
50 | //Add similar matrices. | |
51 | public function add ( mat:matrix ) : matrix | |
52 | { | |
53 | ||
54 | if ( mat.width != W || mat.height != H ) | |
55 | throw new Error ( "Mismatched dimensions for adding.", 2 ); | |
56 | ||
57 | var ret:matrix = new matrix ( W, H ); | |
58 | ||
59 | for ( var x:uint = 0; x < W; x ++ ) | |
60 | { | |
61 | ||
62 | for ( var y:uint = 0; y < H; y ++ ) | |
63 | { | |
64 | ||
65 | ret.setElement ( x, y, data [ x + y * H ] + mat.getElement ( x, y ) ); | |
66 | ||
67 | } | |
68 | ||
69 | } | |
70 | ||
71 | return ret; | |
72 | ||
73 | }; | |
74 | ||
75 | //Subtract similar matrices | |
76 | public function sub ( mat:matrix ) : matrix | |
77 | { | |
78 | ||
79 | if ( mat.width != W || mat.height != H ) | |
80 | throw new Error ( "Mismatched dimensions for adding.", 3 ); | |
81 | ||
82 | var ret:matrix = new matrix ( W, H ); | |
83 | ||
84 | for ( var x:uint = 0; x < W; x ++ ) | |
85 | { | |
86 | ||
87 | for ( var y:uint = 0; y < H; y ++ ) | |
88 | { | |
89 | ||
90 | ret.setElement ( x, y, data [ x + y * H ] - mat.getElement ( x, y ) ); | |
91 | ||
92 | } | |
93 | ||
94 | } | |
95 | ||
96 | return ret; | |
97 | ||
98 | }; | |
99 | ||
100 | //Multiply all the elements of an array my a value. | |
101 | public function mulUniform ( val:Number ):matrix | |
102 | { | |
103 | ||
104 | var ret:matrix = new matrix ( W, H ); | |
105 | ||
106 | for ( var n:uint = 0; n < W * H; n ++ ) | |
107 | { | |
108 | ||
109 | ret.setElement ( n % W, ( n - n % W ) / W, val * data [ n ] ); | |
110 | ||
111 | } | |
112 | ||
113 | return ret; | |
114 | ||
115 | }; | |
116 | ||
117 | //Multiply two matrices. | |
118 | public function mulMatrix ( mat:matrix ) : matrix | |
119 | { | |
120 | ||
121 | if ( W != mat.height ) | |
122 | throw new Error ( "Mismatched dimensions for multiplication.", 4 ); | |
123 | ||
124 | var ret:matrix = new matrix ( mat.width, H ); | |
125 | var curr:Number; | |
126 | ||
127 | for ( var x:uint = 0; x < mat.width; x ++ ) | |
128 | for ( var y:uint = 0; y < H; y ++ ) | |
129 | { | |
130 | ||
131 | curr = 0; | |
132 | ||
133 | for ( var n:uint = 0; n < W; n ++ ) | |
134 | curr += mat.getElement ( x, n ) * data [ n * W + y ]; | |
135 | ||
136 | ret.setElement ( x, y, curr ); | |
137 | ||
138 | } | |
139 | ||
140 | return ret; | |
141 | ||
142 | }; | |
143 | ||
144 | //Get the inverse of the matrix. ( Only works with 1x1, 2x2, or 3x3 matrices. | |
145 | public function inverse () : matrix | |
146 | { | |
147 | ||
148 | if ( !operationSupported ( opInv ) ) | |
149 | throw new Error ( "inversion is not possible on this matrix.", 5 ); | |
150 | ||
151 | var ret:matrix = new matrix ( W, H ); | |
152 | var mul:Number; | |
153 | ||
154 | if ( W == 1 ) | |
155 | ret.setElement ( 0, 0, 1 / data [ 0 ] ); | |
156 | ||
157 | if ( W == 2 ) | |
158 | { | |
159 | ||
160 | mul = 1 / ( data [ 0 ] * data [ 3 ] - data [ 1 ] * data [ 2 ] ); | |
161 | ||
162 | ret.setElement ( 0, 0, data [ 3 ] * mul ); | |
163 | ret.setElement ( 1, 0, -data [ 1 ] * mul ); | |
164 | ||
165 | ret.setElement ( 0, 1, -data [ 2 ] * mul ); | |
166 | ret.setElement ( 1, 1, data [ 0 ] * mul ); | |
167 | ||
168 | } | |
169 | ||
170 | if ( W == 3 ) | |
171 | { | |
172 | ||
173 | mul = 1 / ( data [ 0 ] * ( ( data [ 4 ] * data [ 8 ] ) - ( data [ 5 ] * data [ 7 ] ) ) + data [ 1 ] * ( ( data [ 5 ] * data [ 6 ] ) - ( data [ 8 ] * data [ 3 ] ) ) + data [ 2 ] * ( ( data [ 3 ] * data [ 7 ] ) - ( data [ 4 ] * data [ 6 ] ) ) ); | |
174 | ||
175 | ret.setElement ( 0, 0, ( data [ 4 ] * data [ 8 ] - data [ 5 ] * data [ 7 ] ) ); | |
176 | ret.setElement ( 0, 1, ( data [ 2 ] * data [ 7 ] - data [ 1 ] * data [ 8 ] ) ); | |
177 | ret.setElement ( 0, 2, ( data [ 1 ] * data [ 5 ] - data [ 2 ] * data [ 4 ] ) ); | |
178 | ||
179 | ret.setElement ( 1, 0, ( data [ 5 ] * data [ 6 ] - data [ 3 ] * data [ 8 ] ) ); | |
180 | ret.setElement ( 1, 1, ( data [ 0 ] * data [ 8 ] - data [ 2 ] * data [ 6 ] ) ); | |
181 | ret.setElement ( 1, 2, ( data [ 2 ] * data [ 3 ] - data [ 0 ] * data [ 5 ] ) ); | |
182 | ||
183 | ret.setElement ( 2, 0, ( data [ 3 ] * data [ 7 ] - data [ 4 ] * data [ 6 ] ) ); | |
184 | ret.setElement ( 2, 1, ( data [ 6 ] * data [ 1 ] - data [ 0 ] * data [ 7 ] ) ); | |
185 | ret.setElement ( 2, 2, ( data [ 0 ] * data [ 4 ] - data [ 1 ] * data [ 3 ] ) ); | |
186 | ||
187 | ret = ret.mulUniform ( mul ); | |
188 | ||
189 | } | |
190 | ||
191 | return ret; | |
192 | ||
193 | } | |
194 | ||
195 | //Get the value of a specific element, similarly to setElement. | |
196 | public function getElement ( x:uint, y:uint ) : Number | |
197 | { | |
198 | ||
199 | return data [ x + y * W ]; | |
200 | ||
201 | }; | |
202 | ||
203 | //Width getter | |
204 | public function get width () : uint | |
205 | { | |
206 | ||
207 | return W; | |
208 | ||
209 | }; | |
210 | ||
211 | //Height getter | |
212 | public function get height () : uint | |
213 | { | |
214 | ||
215 | return H; | |
216 | ||
217 | }; | |
218 | ||
219 | //Returns the raw number data in an array. | |
220 | public function getRawData () : Vector.<Number> | |
221 | { | |
222 | ||
223 | return data; | |
224 | ||
225 | }; | |
226 | ||
227 | /*Test if a matrix can have a certain operation | |
228 | preformed on it. This includes multiplication, | |
229 | addition and subtraction with other matricies, | |
230 | getting the inverse, and converting to flash | |
231 | display transform matrices. | |
232 | */ | |
233 | public function operationSupported ( operation:String, second:matrix = null ) : Boolean | |
234 | { | |
235 | ||
236 | if ( !( operation == opFMX || operation == opFM3 || operation == opInv || second != null ) ) | |
237 | throw new Error ( "Second matrix not provided to test for operability.", 6 ); | |
238 | ||
239 | switch ( operation ) | |
240 | { | |
241 | ||
242 | case opInv: | |
243 | if ( ( W == 3 && H == 3 ) || ( W == 2 && H == 2 ) || ( W == 1 && H == 1 ) ) | |
244 | return true; | |
245 | else | |
246 | return false; | |
247 | break; | |
248 | ||
249 | case opAdd: | |
250 | if ( W == second.width && H == second.height ) | |
251 | return true; | |
252 | else | |
253 | return false; | |
254 | break; | |
255 | ||
256 | case opSub: | |
257 | if ( W == second.width && H == second.height ) | |
258 | return true; | |
259 | else | |
260 | return false; | |
261 | break; | |
262 | ||
263 | case opMul: | |
264 | ||
265 | if ( W == second.height ) | |
266 | return true; | |
267 | else | |
268 | return false; | |
269 | ||
270 | case opFMX: | |
271 | ||
272 | if ( W == 3 && H == 3 || W == 3 && H == 2 ) | |
273 | return true; | |
274 | else | |
275 | return false; | |
276 | break; | |
277 | ||
278 | case opFM3: | |
279 | ||
280 | if ( W == 4 && H == 4 ) | |
281 | return true; | |
282 | else | |
283 | return false; | |
284 | ||
285 | break; | |
286 | ||
287 | default: | |
288 | ||
289 | throw new Error ( operation + " is not an operation you can test for.", 7 ); | |
290 | ||
291 | break; | |
292 | ||
293 | } | |
294 | ||
295 | return false; | |
296 | ||
297 | }; | |
298 | ||
299 | public function toString () : String | |
300 | { | |
301 | ||
302 | var out:String = ( newLine ) ? '' : '[ '; | |
303 | var maxL:Vector.<uint> = new Vector.<uint> ( W, true ); | |
304 | ||
305 | var qx:uint; | |
306 | var sp:String; | |
307 | var sa:String; | |
308 | ||
309 | for ( var n:uint = 0; n < W * H; n ++ ) | |
310 | { | |
311 | ||
312 | qx = n % W; | |
313 | maxL [ qx ] = Math.max ( maxL [ qx ], data [ n ].toString ().length ); | |
314 | ||
315 | } | |
316 | ||
317 | for ( var y:uint = 0; y < H; y ++ ) | |
318 | for ( var x:uint = 0; x < W; x ++ ) | |
319 | { | |
320 | ||
321 | sp = ''; | |
322 | sa = data [ x + y * W ].toString ( 10 ); | |
323 | ||
324 | while ( sa.length < maxL [ x ] && newLine ) | |
325 | sa = ' ' + sa; | |
326 | ||
327 | if ( x == 0 ) | |
328 | out += '[ '; | |
329 | ||
330 | out += sa; | |
331 | ||
332 | if ( x < W - 1 ) | |
333 | out += ', '; | |
334 | else | |
335 | { | |
336 | ||
337 | out += ' ]'; | |
338 | if ( y < H - 1 ) | |
339 | out += ( newLine ) ? '\n' : ' '; | |
340 | ||
341 | } | |
342 | ||
343 | } | |
344 | ||
345 | out += ( newLine ) ? '' : ' ]'; | |
346 | ||
347 | var t:String = ''; | |
348 | ||
349 | if ( out.indexOf ( "\n" ) != 0 ) | |
350 | { | |
351 | ||
352 | var u:uint = 0; | |
353 | while ( u ++ < out.indexOf ( "\n" ) ) | |
354 | t += '-'; | |
355 | ||
356 | } | |
357 | else | |
358 | { | |
359 | ||
360 | var g:uint = 0; | |
361 | while ( g ++ < out.length ) | |
362 | t += '-'; | |
363 | ||
364 | } | |
365 | ||
366 | if ( newLine ) | |
367 | out = "Matrix:\n" + t + '\n' + out + '\n' + t; | |
368 | ||
369 | return out; | |
370 | ||
371 | }; | |
372 | ||
373 | //Makes the matrix into a flash transform matrix. | |
374 | public function toFlashMatrix () : flash.geom.Matrix | |
375 | { | |
376 | ||
377 | if ( ! operationSupported ( opFMX ) ) | |
378 | throw new Error ( "Cannot convert to flash matrix. ( wrond dimentions )", 8 ); | |
379 | ||
380 | var ret:flash.geom.Matrix = new flash.geom.Matrix ( data [ 0 ], data [ 1 ], data [ 3 ], data [ 4 ], data [ 2 ], data [ 5 ] ); | |
381 | return ret; | |
382 | ||
383 | } | |
384 | ||
385 | //Makes the matrix a Flash 3D transform matrix. | |
386 | public function toFlashMatrix3D () : flash.geom.Matrix3D | |
387 | { | |
388 | ||
389 | if ( ! operationSupported ( opFM3 ) ) | |
390 | throw new Error ( "Cannot convert to flash matrix. ( wrond dimentions )", 9 ); | |
391 | ||
392 | var ret:flash.geom.Matrix3D = new flash.geom.Matrix3D ( data ); | |
393 | return ret; | |
394 | ||
395 | } | |
396 | ||
397 | //Generates an identity matrix of a specific size. | |
398 | public static function generateIdentity ( size:uint ) : matrix | |
399 | { | |
400 | ||
401 | var ret:matrix = new matrix ( size, size ); | |
402 | var i:uint = 0; | |
403 | ||
404 | while ( i ++ < size ) | |
405 | ret.setElement ( i - 1, i - 1, 1 ); | |
406 | ||
407 | return ret; | |
408 | ||
409 | }; | |
410 | ||
411 | //Creates a matrix from a flash transform matrix. | |
412 | public static function fromFlashMatrix ( mat:flash.geom.Matrix ) : matrix | |
413 | { | |
414 | ||
415 | return new matrix ( 3, 3, mat.a, mat.b, mat.tx, mat.c, mat.d, mat.ty, 0, 0, 1 ); | |
416 | ||
417 | } | |
418 | ||
419 | //Creates a matrix from a flash 3D transform matrix. | |
420 | public static function fromFlashMatrix3D ( mat:flash.geom.Matrix3D ) : matrix | |
421 | { | |
422 | ||
423 | return new matrix ( 4, 4, mat.rawData ); | |
424 | ||
425 | } | |
426 | ||
427 | }; | |
428 | ||
429 | }; |