1 /** 2 * Copyright (C) 2009-2011 Klaus Reimer <k@ailis.de> 3 * See LICENSE.txt for licensing information. 4 * 5 * @require twodee.js 6 * @require twodee/Vector.js 7 */ 8 9 /** 10 * Constructs a new matrix initialized as an identity matrix. 11 * 12 * @constructor 13 * @class 14 * A matrix with 3x3 entries. 15 */ 16 twodee.Matrix = function() 17 { 18 twodee.Matrix.counter++; 19 this.translation = new twodee.Vector(); 20 }; 21 22 /** 23 * Instance counter. 24 * 25 * @type {number} 26 */ 27 twodee.Matrix.counter = 0; 28 29 /** 30 * A temporary matrix for internal operations. 31 * 32 * @private 33 * @type {twodee.Matrix} 34 */ 35 twodee.Matrix.TMP = new twodee.Matrix(); 36 37 /** 38 * Cached translation vector. 39 * @private 40 * @type {twodee.Vector} 41 */ 42 twodee.Matrix.prototype.translation; 43 44 /** 45 * The matrix entry 0;0. 46 * 47 * @type {number} 48 */ 49 twodee.Matrix.prototype.m00 = 1; 50 51 /** 52 * The matrix entry 0;1. 53 * 54 * @type {number} 55 */ 56 twodee.Matrix.prototype.m01 = 0; 57 58 /** 59 * The matrix entry 0;2. 60 * 61 * @type {number} 62 */ 63 twodee.Matrix.prototype.m02 = 0; 64 65 /** 66 * The matrix entry 1;0. 67 * 68 * @type {number} 69 */ 70 twodee.Matrix.prototype.m10 = 0; 71 72 /** 73 * The matrix entry 1;1. 74 * 75 * @type {number} 76 */ 77 twodee.Matrix.prototype.m11 = 1; 78 79 /** 80 * The matrix entry 1;2. 81 * 82 * @type {number} 83 */ 84 twodee.Matrix.prototype.m12 = 0; 85 86 /** 87 * The matrix entry 0;0. 88 * 89 * @type {number} 90 */ 91 twodee.Matrix.prototype.m20 = 0; 92 93 /** 94 * The matrix entry 0;1. 95 * 96 * @type {number} 97 */ 98 twodee.Matrix.prototype.m21 = 0; 99 100 /** 101 * The matrix entry 0;2. 102 * 103 * @type {number} 104 */ 105 twodee.Matrix.prototype.m22 = 1; 106 107 /** 108 * Returns a copy of this matrix. If a target matrix is specified then the 109 * matrix is copied into this target matrix. If not specified then a new 110 * fresh matrix is created. 111 * 112 * @param {twodee.Matrix} target 113 * Optional target matrix 114 * @return {twodee.Matrix} A copy of this matrix 115 */ 116 twodee.Matrix.prototype.copy = function(target) 117 { 118 return (target ? target : new twodee.Matrix()).set( 119 this.m00, this.m01, this.m02, 120 this.m10, this.m11, this.m12, 121 this.m20, this.m21, this.m22); 122 }; 123 124 /** 125 * Sets the matrix entries. 126 * 127 * @param {number} m00 128 * The matrix entry 0;0 129 * @param {number} m01 130 * The matrix entry 0;1 131 * @param {number} m02 132 * The matrix entry 0;2 133 * @param {number} m10 134 * The matrix entry 1;0 135 * @param {number} m11 136 * The matrix entry 1;1 137 * @param {number} m12 138 * The matrix entry 1;2 139 * @param {number} m20 140 * The matrix entry 2;0 141 * @param {number} m21 142 * The matrix entry 2;1 143 * @param {number} m22 144 * The matrix entry 2;2 145 * @return {twodee.Matrix} 146 * This matrix 147 */ 148 twodee.Matrix.prototype.set = function(m00, m01, m02, m10, m11, m12, 149 m20, m21, m22) 150 { 151 this.m00 = m00; 152 this.m01 = m01; 153 this.m02 = m02; 154 this.m10 = m10; 155 this.m11 = m11; 156 this.m12 = m12; 157 this.m20 = m20; 158 this.m21 = m21; 159 this.m22 = m22; 160 return this; 161 }; 162 163 /** 164 * Sets the matrix entries. 165 * 166 * @param {twodee.Matrix} transform 167 * The matrix to get the entries from 168 * @return {twodee.Matrix} 169 * This matrix 170 */ 171 twodee.Matrix.prototype.setTransform = function(transform) 172 { 173 this.m00 = transform.m00; 174 this.m01 = transform.m01; 175 this.m02 = transform.m02; 176 this.m10 = transform.m10; 177 this.m11 = transform.m11; 178 this.m12 = transform.m12; 179 this.m20 = transform.m20; 180 this.m21 = transform.m21; 181 this.m22 = transform.m22; 182 return this; 183 }; 184 185 /** 186 * Sets the entries of this matrix to an identity matrix. 187 * 188 * @return {twodee.Matrix} 189 * The matrix 190 */ 191 twodee.Matrix.prototype.setIdentity = function() 192 { 193 return this.set( 194 1, 0, 0, 195 0, 1, 0, 196 0, 0, 1); 197 }; 198 199 /** 200 * Sets the entries of this matrix to a rotation matrix. 201 * 202 * @param {number} angle 203 * The rotation angle in anti-clockwise RAD 204 * @return {twodee.Matrix} 205 * This matrix 206 */ 207 twodee.Matrix.prototype.setRotate = function(angle) 208 { 209 var s, c; 210 211 s = Math.sin(angle); 212 c = Math.cos(angle); 213 return this.set( 214 c, -s, 0, 215 s, c, 0, 216 0, 0, 1); 217 }; 218 219 /** 220 * Returns the rotation angle in anti-clockwise RAD. 221 * 222 * @return {number} The rotation angle in anti-clockwise RAD 223 */ 224 twodee.Matrix.prototype.getRotationAngle = function() 225 { 226 return Math.atan2(this.m10, this.m00); 227 }; 228 229 /** 230 * Sets the entries of this matrix to a scaling matrix. 231 * 232 * @param {number} fx 233 * The X scale factor 234 * @param {number=} fy 235 * The Y scale factor. Optional. Defaults to fx. 236 * @return {twodee.Matrix} 237 * This matrix 238 */ 239 twodee.Matrix.prototype.setScale = function(fx, fy) 240 { 241 return this.set( 242 fx, 0, 0, 243 0, fy === undefined ? fx : fy, 0, 244 0, 0, 1); 245 }; 246 247 /** 248 * Sets the entries of this matrix to a X scaling matrix. 249 * 250 * @param {number} f 251 * The scale factor 252 * @return {twodee.Matrix} 253 * This matrix 254 */ 255 twodee.Matrix.prototype.setScaleX = function(f) 256 { 257 return this.set( 258 f, 0, 0, 259 0, 1, 0, 260 0, 0, 1); 261 }; 262 263 /** 264 * Sets the entries of this matrix to a Y scaling matrix. 265 * 266 * @param {number} f 267 * The scale factor 268 * @return {twodee.Matrix} 269 * This matrix 270 */ 271 twodee.Matrix.prototype.setScaleY = function(f) 272 { 273 return this.set( 274 1, 0, 0, 275 0, f, 0, 276 0, 0, 1); 277 }; 278 279 /** 280 * Sets the entries of this matrix to a translation matrix. 281 * 282 * @param {number} dx 283 * The X delta 284 * @param {number} dy 285 * The Y delta. 286 * @return {twodee.Matrix} 287 * This matrix 288 */ 289 twodee.Matrix.prototype.setTranslate = function(dx, dy) 290 { 291 return this.set( 292 1, 0, dx, 293 0, 1, dy, 294 0, 0, 1); 295 }; 296 297 /** 298 * Returns the X translation of the matrix. 299 * 300 * @return {number} The X translation 301 */ 302 twodee.Matrix.prototype.getTranslationX = function() 303 { 304 return this.m02; 305 }; 306 307 /** 308 * Returns the Y translation of the matrix. 309 * 310 * @return {number} The Y translation 311 */ 312 twodee.Matrix.prototype.getTranslationY = function() 313 { 314 return this.m12; 315 }; 316 317 /** 318 * Returns The translation vector of the current matrix. Attention! This 319 * vector is reused and updated to the current translation whenever this 320 * method is called. So you may want to clone the vector if you need it for 321 * a longer time. 322 * 323 * @return {twodee.Vector} The translation vector of the matrix 324 */ 325 twodee.Matrix.prototype.getTranslation = function() 326 { 327 return this.translation.set(this.m02, this.m12); 328 }; 329 330 /** 331 * Sets the entries of this matrix to a X translation matrix. 332 * 333 * @param {number} d 334 * The delta 335 * @return {twodee.Matrix} 336 * This matrix 337 */ 338 twodee.Matrix.prototype.setTranslateX = function(d) 339 { 340 return this.set( 341 1, 0, d, 342 0, 1, 0, 343 0, 0, 1); 344 }; 345 346 /** 347 * Sets the entries of this matrix to a Y translation matrix. 348 * 349 * @param {number} d 350 * The delta 351 * @return {twodee.Matrix} 352 * This matrix 353 */ 354 twodee.Matrix.prototype.setTranslateY = function(d) 355 { 356 return this.set( 357 1, 0, 0, 358 0, 1, d, 359 0, 0, 1); 360 }; 361 362 /** 363 * Multiplies this matrix with the specified matrix. The result is written 364 * to this matrix. 365 * 366 * @param {twodee.Matrix} m 367 * The other matrix 368 * @return {twodee.Matrix} 369 * This matrix 370 */ 371 twodee.Matrix.prototype.transform = function(m) 372 { 373 return this.set( 374 this.m00 * m.m00 + this.m01 * m.m10 + this.m02 * m.m20, 375 this.m00 * m.m01 + this.m01 * m.m11 + this.m02 * m.m21, 376 this.m00 * m.m02 + this.m01 * m.m12 + this.m02 * m.m22, 377 378 this.m10 * m.m00 + this.m11 * m.m10 + this.m12 * m.m20, 379 this.m10 * m.m01 + this.m11 * m.m11 + this.m12 * m.m21, 380 this.m10 * m.m02 + this.m11 * m.m12 + this.m12 * m.m22, 381 382 this.m20 * m.m00 + this.m21 * m.m10 + this.m22 * m.m20, 383 this.m20 * m.m01 + this.m21 * m.m11 + this.m22 * m.m21, 384 this.m20 * m.m02 + this.m21 * m.m12 + this.m22 * m.m22); 385 }; 386 387 /** 388 * Multiplies this matrix with the specified factor. 389 * 390 * @param {number} f 391 * The factor 392 * @return {twodee.Matrix} 393 * This matrix 394 */ 395 twodee.Matrix.prototype.multiply = function(f) 396 { 397 this.m00 *= f; 398 this.m01 *= f; 399 this.m02 *= f; 400 this.m10 *= f; 401 this.m11 *= f; 402 this.m12 *= f; 403 this.m20 *= f; 404 this.m21 *= f; 405 this.m22 *= f; 406 return this; 407 }; 408 409 /** 410 * Divides this matrix by the specified factor. 411 * 412 * @param {number} f 413 * The factor 414 * @return {twodee.Matrix} 415 * This matrix 416 */ 417 twodee.Matrix.prototype.divide = function(f) 418 { 419 this.m00 /= f; 420 this.m01 /= f; 421 this.m02 /= f; 422 this.m10 /= f; 423 this.m11 /= f; 424 this.m12 /= f; 425 this.m20 /= f; 426 this.m21 /= f; 427 this.m22 /= f; 428 return this; 429 }; 430 431 /** 432 * Translates this matrix by the specified deltas 433 * 434 * @param {number} dx 435 * The X delta 436 * @param {number} dy 437 * The Y delta 438 * @return {twodee.Matrix} 439 * This matrix 440 */ 441 twodee.Matrix.prototype.translate = function(dx, dy) 442 { 443 return this.transform(twodee.Matrix.TMP.setTranslate(dx, dy)); 444 }; 445 446 /** 447 * X-Translates this matrix by the specified delta 448 * 449 * @param {number} d 450 * The delta 451 * @return {twodee.Matrix} 452 * This matrix 453 */ 454 twodee.Matrix.prototype.translateX = function(d) 455 { 456 return this.transform(twodee.Matrix.TMP.setTranslateX(d)); 457 }; 458 459 /** 460 * Y-Translates this matrix by the specified delta 461 * 462 * @param {number} d 463 * The delta 464 * @return {twodee.Matrix} 465 * This matrix 466 */ 467 twodee.Matrix.prototype.translateY = function(d) 468 { 469 return this.transform(twodee.Matrix.TMP.setTranslateY(d)); 470 }; 471 472 /** 473 * Scales this matrix by the specified factors 474 * 475 * @param {number} fx 476 * The X factor 477 * @param {number=} fy 478 * The Y factor. Optional. Defaults to fx. 479 * @return {twodee.Matrix} 480 * This matrix 481 */ 482 twodee.Matrix.prototype.scale = function(fx, fy) 483 { 484 return this.transform(twodee.Matrix.TMP.setScale(fx, 485 fy === undefined ? fx : fy)); 486 }; 487 488 /** 489 * X-Scales this matrix by the specified factor 490 * 491 * @param {number} f 492 * The factor 493 * @return {twodee.Matrix} 494 * This matrix 495 */ 496 twodee.Matrix.prototype.scaleX = function(f) 497 { 498 return this.transform(twodee.Matrix.TMP.setScaleX(f)); 499 }; 500 501 /** 502 * Y-Scales this matrix by the specified factor 503 * 504 * @param {number} f 505 * The factor 506 * @return {twodee.Matrix} 507 * This matrix 508 */ 509 twodee.Matrix.prototype.scaleY = function(f) 510 { 511 return this.transform(twodee.Matrix.TMP.setScaleY(f)); 512 }; 513 514 /** 515 * Rotates this matrix by the specified angle 516 * 517 * @param {number} r 518 * The angle in anti-clockwise RAD 519 * @return {twodee.Matrix} 520 * This matrix 521 */ 522 twodee.Matrix.prototype.rotate = function(r) 523 { 524 return this.transform(twodee.Matrix.TMP.setRotate(r)); 525 }; 526 527 /** 528 * Returns the determinant of the matrix. 529 * 530 * @return {number} The determinant of the matrix 531 */ 532 twodee.Matrix.prototype.getDeterminant = function() 533 { 534 return this.m00 * this.m11 * this.m22 + this.m01 * this.m12 * this.m20 + 535 this.m02 * this.m10 * this.m21 - this.m00 * this.m12 * this.m21 - 536 this.m01 * this.m10 * this.m22 - this.m02 * this.m11 * this.m20; 537 }; 538 539 /** 540 * Inverts this matrix. 541 * 542 * @return {twodee.Matrix} 543 * This matrix 544 */ 545 twodee.Matrix.prototype.invert = function() 546 { 547 var d; 548 549 d = this.getDeterminant(); 550 return this.set( 551 this.m11*this.m22 - this.m12*this.m21, 552 this.m02*this.m21 - this.m01*this.m22, 553 this.m01*this.m12 - this.m02*this.m11, 554 this.m12*this.m20 - this.m10*this.m22, 555 this.m00*this.m22 - this.m02*this.m20, 556 this.m02*this.m10 - this.m00*this.m12, 557 this.m10*this.m21 - this.m11*this.m20, 558 this.m01*this.m20 - this.m00*this.m21, 559 this.m00*this.m11 - this.m01*this.m10).divide(d); 560 }; 561