test_DOMMatrix.html (21124B)
1 <!DOCTYPE HTML> 2 <html> 3 <head> 4 <title>Test DOMMatrix behavior</title> 5 <script src="/tests/SimpleTest/SimpleTest.js"></script> 6 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"> 7 </head> 8 <script> 9 function createMatrix(a, b, c, d, e, f) 10 { 11 var m = new DOMMatrix(); 12 m.a = a; 13 m.b = b; 14 m.c = c; 15 m.d = d; 16 m.e = e; 17 m.f = f; 18 return m; 19 } 20 21 function create3DMatrix(a, b, c, d, e, f) 22 { 23 var m = new DOMMatrix(); 24 m.a = a; 25 m.b = b; 26 m.c = c; 27 m.d = d; 28 m.e = e; 29 m.f = f; 30 m.m13 = 0; 31 return m; 32 } 33 34 function cmpMatrix(a, b, msg) 35 { 36 if (Array.isArray(a)) 37 a = new DOMMatrix(a); 38 if (Array.isArray(b)) 39 b = new DOMMatrix(b); 40 41 ok(CompareDOMMatrix(a, b), 42 msg + " - got " + formatMatrix(a) 43 + ", expected " + formatMatrix(b)); 44 } 45 46 function roughCmpMatrix(a, b, msg) 47 { 48 if (Array.isArray(a)) 49 a = new DOMMatrix(a); 50 if (Array.isArray(b)) 51 b = new DOMMatrix(b); 52 53 ok(RoughCompareDOMMatrix(a, b), 54 msg + " - got " + formatMatrix(a) 55 + ", expected " + formatMatrix(b)); 56 } 57 58 function formatMatrix(m) 59 { 60 m = new DOMMatrix(m); 61 62 if (m.is2D) 63 return "(" + [m.a, m.b, m.c, m.d, m.e, m.f].join(', ') + ")"; 64 else 65 return "(" + [m.m11, m.m12, m.m13, m.m14, 66 m.m21, m.m22, m.m23, m.m24, 67 m.m31, m.m32, m.m33, m.m34, 68 m.m41, m.m42, m.m43, m.m44,].join(', ') + ")"; 69 } 70 71 function CompareMatrix(dm, m) 72 { 73 var ma = m.toFloat32Array(); 74 for (var x = 0; x < ma.length; x++) { 75 if (Math.abs(ma[x] - dm.m[x]) > 0.000001) 76 return false; 77 } 78 79 return true; 80 } 81 82 function CompareDOMMatrix(dm1, dm2) 83 { 84 var m1 = dm1.toFloat32Array(); 85 var m2 = dm2.toFloat32Array(); 86 87 if (m1.length != m2.length) 88 return false; 89 90 for (var x = 0; x < m1.length; x++) { 91 if (Math.abs(m1[x] - m2[x]) > 0.000001) 92 return false; 93 } 94 95 return true; 96 } 97 98 function RoughCompareDOMMatrix(dm1, dm2) 99 { 100 var m1 = dm1.toFloat32Array(); 101 var m2 = dm2.toFloat32Array(); 102 103 if (m1.length != m2.length) 104 return false; 105 106 const tolerance = 1 / 65535; 107 for (var x = 0; x < m1.length; x++) { 108 if (Math.abs(m1[x] - m2[x]) > tolerance) 109 return false; 110 } 111 112 return true; 113 } 114 115 SimpleTest.waitForExplicitFinish(); 116 117 function main() 118 { 119 var tests = [ 120 testCreateMatrix, 121 testMultiply, 122 testInverse, 123 testTranslate, 124 testScale, 125 testScaleNonUniform, 126 testRotate, 127 testRotateFromVector, 128 testFlipX, 129 testFlipY, 130 testSkewX, 131 testSkewY, 132 testMultiplyInPlace, 133 testInverseInPlace, 134 testTranslateInPlace, 135 testScaleInPlace, 136 testRotateInPlace, 137 testRotateFromVectorInPlace, 138 testSkewXInPlace, 139 testSkewYInPlace, 140 testCreateMatrix3D, 141 testMultiply3D, 142 testInverse3D, 143 testTranslate3D, 144 testScale3D, 145 test3D, 146 testParsing, 147 testStringify 148 ]; 149 for (var i = 0; i < tests.length; i++) { 150 try{ 151 tests[i](); 152 } catch (e) { 153 ok(false, "uncaught exception in test " + i + ": " + e.name); 154 } 155 } 156 SimpleTest.finish(); 157 } 158 159 function testCreateMatrix() 160 { 161 var m = new DOMMatrix(); 162 163 // Should be initialised to identity 164 cmpMatrix(m, [1, 0, 0, 1, 0, 0], 165 "DOMMatrix should produce identity matrix"); 166 167 m = new DOMMatrix([1,2,3,4,5,6]); 168 cmpMatrix(m, [1,2,3,4,5,6], 169 "DOMMatrix should produce the same matrix"); 170 ok(m.is2D, "Failed to mark matrix as 2D."); 171 172 m = new DOMMatrix([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]); 173 cmpMatrix(m, [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16], 174 "DOMMatrix should produce the same matrix"); 175 ok(!m.is2D, "Failed to mark matrix as 3D."); 176 177 var n = new DOMMatrix(m.toFloat32Array()); 178 cmpMatrix(n, [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16], 179 "DOMMatrix should produce the same matrix with float32array constructor"); 180 ok(!n.is2D, "Failed to mark matrix as 3D."); 181 182 var n = new DOMMatrix(m.toFloat64Array()); 183 cmpMatrix(n, [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16], 184 "DOMMatrix should produce the same matrix with float64array constructor"); 185 ok(!n.is2D, "Failed to mark matrix as 3D."); 186 187 var exn = null; 188 try { 189 m = new DOMMatrix([0]); 190 } catch (e) { 191 exn = e; 192 } 193 ok(exn, "did throw exception with bad DOMMatrix constructor with 1 parameter"); 194 195 exn = null; 196 try { 197 m = new DOMMatrix([1,2,3,4,5,6,7,8,9]); 198 } catch (e) { 199 exn = e; 200 } 201 ok(exn, "did throw exception with bad DOMMatrix constructor with 9 parameters"); 202 203 exn = null; 204 try { 205 m = new DOMMatrix([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]); 206 } catch (e) { 207 exn = e; 208 } 209 ok(exn, "did throw exception with bad DOMMatrix constructor with 17 parameters"); 210 } 211 212 // DOMMatrix multiply(in DOMMatrix secondMatrix); 213 function testMultiply() 214 { 215 var m1 = createMatrix(1, 0, 0, 1, 50, 90); 216 var m2 = createMatrix(Math.SQRT1_2, -Math.SQRT1_2, Math.SQRT1_2, Math.SQRT1_2, 0, 0); 217 var m3 = createMatrix(1, 0, 0, 1, 130, 160); 218 var result = m1.multiply(m2).multiply(m3); 219 roughCmpMatrix(result, [Math.SQRT1_2, -Math.SQRT1_2, Math.SQRT1_2, Math.SQRT1_2, 255.060974, 111.213203], 220 "Unexpected result after multiplying matrices"); 221 222 // Check orig matrices are unchanged 223 cmpMatrix(m1, [1, 0, 0, 1, 50, 90], "Matrix changed after multiplication"); 224 roughCmpMatrix(m2, [Math.SQRT1_2, -Math.SQRT1_2, Math.SQRT1_2, Math.SQRT1_2, 0, 0], 225 "Matrix changed after multiplication"); 226 cmpMatrix(m3, [1, 0, 0, 1, 130, 160], "Matrix changed after multiplication"); 227 } 228 229 // DOMMatrix inverse() raises(SVGException); 230 function testInverse() 231 { 232 // Test inversion 233 var m = createMatrix(2, 0, 0, 4, 110, -50); 234 roughCmpMatrix(m.inverse(), [0.5, 0, 0, 0.25, -55, 12.5], 235 "Unexpected result after inverting matrix"); 236 237 // Test non-invertable 238 m = createMatrix(0, 0, 1, 0, 0, 0); 239 m = m.inverse(); 240 ok(isNaN(m.a), "Failed to invalidate inverted singular matrix, got " + m.a); 241 ok(!m.is2D, "Failed to mark invalidated inverted singular matrix as 3D."); 242 } 243 244 // DOMMatrix translate(in float x, in float y); 245 function testTranslate() 246 { 247 var m = createMatrix(2, 0, 0, 1, 120, 100); 248 roughCmpMatrix(m.translate(100, -50), [2, 0, 0, 1, 320, 50], 249 "Unexpected result after translate"); 250 } 251 252 // DOMMatrix scale(in float scaleFactor); 253 function testScale() 254 { 255 var m = createMatrix(2, 0, 0, 1, 120, 100); 256 roughCmpMatrix(m.scale(0.5), [1, 0, 0, 0.5, 120, 100], 257 "Unexpected result after scale"); 258 } 259 260 // DOMMatrix scaleNonUniform(in float scaleFactorX, in float scaleFactorY); 261 function testScaleNonUniform() 262 { 263 var m = createMatrix(2, 0, 0, 1, 120, 100); 264 roughCmpMatrix(m.scaleNonUniform(0.5, -3), [1, 0, 0, -3, 120, 100], 265 "Unexpected result after scaleNonUniform"); 266 } 267 268 // DOMMatrix rotate(in float angle); 269 function testRotate() 270 { 271 var m = createMatrix(2, 0, 0, 1, 120, 100); 272 roughCmpMatrix(m.rotate(45), 273 [2*Math.cos(Math.PI/4), Math.sin(Math.PI/4), 274 2*-Math.sin(Math.PI/4), Math.cos(Math.PI/4), 275 120, 100], 276 "Unexpected result after rotate"); 277 } 278 279 // DOMMatrix rotateFromVector(in float x, in float y) raises(SVGException); 280 function testRotateFromVector() 281 { 282 var m = createMatrix(2, 0, 0, 1, 120, 100); 283 // Make a 150 degree angle 284 var result = m.rotateFromVector(-2, 1.1547); 285 roughCmpMatrix(result, 286 [2*Math.cos(5*Math.PI/6), Math.sin(5*Math.PI/6), 287 2*-Math.sin(5*Math.PI/6), Math.cos(5*Math.PI/6), 288 120, 100], 289 "Unexpected result after rotateFromVector"); 290 291 // Test bad input (1) 292 var exn = null; 293 try { 294 m.rotateFromVector(1, 0); 295 } catch (e) { 296 exn = e; 297 } 298 is(exn, null, "did not throw exception with zero coord for rotateFromVector"); 299 300 // Test bad input (2) 301 exn = null; 302 try { 303 m.rotateFromVector(0, 1); 304 } catch (e) { 305 exn = e; 306 } 307 is(exn, null, "did not throw exception with zero coord for rotateFromVector"); 308 } 309 310 // DOMMatrix flipX(); 311 function testFlipX() 312 { 313 var m = createMatrix(1, 2, 3, 4, 5, 6); 314 cmpMatrix(m.flipX(), [-1, -2, 3, 4, 5, 6], "Unexpected result after flipX"); 315 } 316 317 // DOMMatrix flipY(); 318 function testFlipY() 319 { 320 var m = createMatrix(1, 2, 3, 4, 5, 6); 321 cmpMatrix(m.flipY(), [1, 2, -3, -4, 5, 6], "Unexpected result after flipY"); 322 } 323 324 // DOMMatrix skewX(in float angle); 325 function testSkewX() 326 { 327 var m = createMatrix(2, 0, 0, 1, 120, 100); 328 roughCmpMatrix(m.skewX(30), [2, 0, 2*Math.tan(Math.PI/6), 1, 120, 100], 329 "Unexpected result after skewX"); 330 } 331 332 // DOMMatrix skewY(in float angle); 333 function testSkewY() 334 { 335 var m = createMatrix(2, 0, 0, 1, 120, 100); 336 roughCmpMatrix(m.skewY(30), [2, Math.tan(Math.PI/6), 0, 1, 120, 100], 337 "Unexpected result after skewY"); 338 } 339 340 // DOMMatrix multiply(in DOMMatrix secondMatrix); 341 function testMultiplyInPlace() 342 { 343 var m1 = createMatrix(1, 0, 0, 1, 50, 90); 344 var m2 = createMatrix(Math.SQRT1_2, -Math.SQRT1_2, Math.SQRT1_2, Math.SQRT1_2, 0, 0); 345 var m3 = createMatrix(1, 0, 0, 1, 130, 160); 346 m1.multiplySelf(m2).multiplySelf(m3); 347 roughCmpMatrix(m1, [Math.SQRT1_2, -Math.SQRT1_2, Math.SQRT1_2, Math.SQRT1_2, 255.060974, 111.213203], 348 "Unexpected result after multiplying matrices"); 349 350 // Check orig matrices are unchanged 351 roughCmpMatrix(m2, [Math.SQRT1_2, -Math.SQRT1_2, Math.SQRT1_2, Math.SQRT1_2, 0, 0], 352 "Matrix changed after multiplication"); 353 cmpMatrix(m3, [1, 0, 0, 1, 130, 160], "Matrix changed after multiplication"); 354 } 355 356 // DOMMatrix inverse() raises(SVGException); 357 function testInverseInPlace() 358 { 359 // Test inversion 360 var m = createMatrix(2, 0, 0, 4, 110, -50); 361 m.invertSelf(); 362 roughCmpMatrix(m, [0.5, 0, 0, 0.25, -55, 12.5], 363 "Unexpected result after inverting matrix"); 364 365 // Test non-invertable 366 m = createMatrix(0, 0, 1, 0, 0, 0); 367 m.invertSelf(); 368 ok(isNaN(m.a), "Failed to invalidate inverted singular matrix, got " + m.a); 369 ok(!m.is2D, "Failed to mark invalidated inverted singular matrix as 3D."); 370 } 371 372 // DOMMatrix translate(in float x, in float y); 373 function testTranslateInPlace() 374 { 375 var m = createMatrix(2, 0, 0, 1, 120, 100); 376 m.translateSelf(100, -50) 377 roughCmpMatrix(m, [2, 0, 0, 1, 320, 50], 378 "Unexpected result after translate"); 379 } 380 381 // DOMMatrix scale(in float scaleFactor); 382 function testScaleInPlace() 383 { 384 var m = createMatrix(2, 0, 0, 1, 120, 100); 385 m.scaleSelf(0.5); 386 roughCmpMatrix(m, [1, 0, 0, 0.5, 120, 100], 387 "Unexpected result after scale"); 388 } 389 390 // DOMMatrix rotate(in float angle); 391 function testRotateInPlace() 392 { 393 var m = createMatrix(2, 0, 0, 1, 120, 100); 394 m.rotateSelf(45); 395 roughCmpMatrix(m, 396 [2*Math.cos(Math.PI/4), Math.sin(Math.PI/4), 397 2*-Math.sin(Math.PI/4), Math.cos(Math.PI/4), 398 120, 100], 399 "Unexpected result after rotate"); 400 } 401 402 // DOMMatrix rotateFromVector(in float x, in float y) raises(SVGException); 403 function testRotateFromVectorInPlace() 404 { 405 var m = createMatrix(2, 0, 0, 1, 120, 100); 406 // Make a 150 degree angle 407 m.rotateFromVectorSelf(-2, 1.1547); 408 roughCmpMatrix(m, 409 [2*Math.cos(5*Math.PI/6), Math.sin(5*Math.PI/6), 410 2*-Math.sin(5*Math.PI/6), Math.cos(5*Math.PI/6), 411 120, 100], 412 "Unexpected result after rotateFromVector"); 413 414 // Test bad input (1) 415 try { 416 m.rotateFromVectorSelf(1, 0); 417 ok(true, "did not throw exception with zero coord for rotateFromVector"); 418 } catch (e) { 419 ok(false, 420 "Got unexpected exception " + e + ", expected NotSupportedError"); 421 } 422 423 // Test bad input (2) 424 try { 425 m.rotateFromVectorSelf(0, 1); 426 ok(true, "did not throw exception with zero coord for rotateFromVector"); 427 } catch (e) { } 428 } 429 430 // DOMMatrix skewX(in float angle); 431 function testSkewXInPlace() 432 { 433 var m = createMatrix(2, 0, 0, 1, 120, 100); 434 m.skewXSelf(30); 435 roughCmpMatrix(m, [2, 0, 2*Math.tan(Math.PI/6), 1, 120, 100], 436 "Unexpected result after skewX"); 437 } 438 439 // DOMMatrix skewY(in float angle); 440 function testSkewYInPlace() 441 { 442 var m = createMatrix(2, 0, 0, 1, 120, 100); 443 m.skewYSelf(30); 444 roughCmpMatrix(m, [2, Math.tan(Math.PI/6), 0, 1, 120, 100], 445 "Unexpected result after skewY"); 446 } 447 448 function testCreateMatrix3D() 449 { 450 var m = new DOMMatrix([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]); 451 452 // Should be initialised to identity 453 cmpMatrix(m, [1, 0, 0, 1, 0, 0], 454 "DOMMatrix should produce identity matrix"); 455 is(m.is2D, false, "should produce 3d matrix"); 456 457 m = new DOMMatrix([1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]); 458 459 // Should be initialised to identity 460 cmpMatrix(m, [1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], 461 "DOMMatrix should produce identity matrix"); 462 is(m.is2D, false, "should produce 3d matrix"); 463 } 464 465 // DOMMatrix multiply(in DOMMatrix secondMatrix); 466 function testMultiply3D() 467 { 468 var m1 = createMatrix(1, 0, 0, 1, 50, 90); 469 var m2 = create3DMatrix(Math.SQRT1_2, -Math.SQRT1_2, Math.SQRT1_2, Math.SQRT1_2, 0, 0); 470 var m3 = create3DMatrix(1, 0, 0, 1, 130, 160); 471 var result = m1.multiply(m2).multiply(m3); 472 ok(m1.is2D == true, "should produce 3d matrix"); 473 roughCmpMatrix(result, [Math.SQRT1_2, -Math.SQRT1_2, Math.SQRT1_2, Math.SQRT1_2, 255.060974, 111.213203], 474 "Unexpected result after multiplying matrices"); 475 476 // Check orig matrices are unchanged 477 cmpMatrix(m1, [1, 0, 0, 1, 50, 90], "Matrix changed after multiplication"); 478 roughCmpMatrix(m2, [Math.SQRT1_2, -Math.SQRT1_2, Math.SQRT1_2, Math.SQRT1_2, 0, 0], 479 "Matrix changed after multiplication"); 480 cmpMatrix(m3, [1, 0, 0, 1, 130, 160], "Matrix changed after multiplication"); 481 } 482 483 // DOMMatrix inverse() raises(SVGException); 484 function testInverse3D() 485 { 486 // Test inversion 487 var m = create3DMatrix(2, 0, 0, 4, 110, -50); 488 roughCmpMatrix(m.inverse(), [0.5, 0, 0, 0.25, -55, 12.5], 489 "Unexpected result after inverting matrix"); 490 491 // Test non-invertable 492 m = createMatrix(0, 0, 1, 0, 0, 0); 493 m = m.inverse(); 494 ok(isNaN(m.a), "Failed to invalidate inverted singular matrix, got " + m.a); 495 ok(!m.is2D, "Failed to mark invalidated inverted singular matrix as 3D."); 496 } 497 498 // DOMMatrix translate(in float x, in float y); 499 function testTranslate3D() 500 { 501 var m = create3DMatrix(2, 0, 0, 1, 120, 100); 502 roughCmpMatrix(m.translate(100, -50), [2, 0, 0, 1, 320, 50], 503 "Unexpected result after translate"); 504 } 505 506 // DOMMatrix scale(in float scaleFactor); 507 function testScale3D() 508 { 509 var m = create3DMatrix(2, 0, 0, 1, 120, 100); 510 roughCmpMatrix(m.scale(0.5), [1, 0, 0, 0.5, 120, 100], 511 "Unexpected result after scale"); 512 } 513 514 function Matrix3D() { 515 this.m = new Float32Array([ 516 1, 0, 0, 0, 517 0, 1, 0, 0, 518 0, 0, 1, 0, 519 0, 0, 0, 1 520 ]); 521 } 522 523 Matrix3D.prototype = { 524 translate(x, y, z, result) { 525 result = result || new Matrix3D(); 526 var m = result.m; 527 528 m[0] = 1; 529 m[1] = 0; 530 m[2] = 0; 531 m[3] = x; 532 533 m[4] = 0; 534 m[5] = 1; 535 m[6] = 0; 536 m[7] = y; 537 538 m[8] = 0; 539 m[9] = 0; 540 m[10] = 1; 541 m[11] = z; 542 543 m[12] = 0; 544 m[13] = 0; 545 m[14] = 0; 546 m[15] = 1; 547 548 return result; 549 }, 550 inverse(matrix, result) { 551 result = result || new Matrix3D(); 552 var m = matrix.m, r = result.m; 553 554 r[0] = m[5]*m[10]*m[15] - m[5]*m[14]*m[11] - m[6]*m[9]*m[15] + m[6]*m[13]*m[11] + m[7]*m[9]*m[14] - m[7]*m[13]*m[10]; 555 r[1] = -m[1]*m[10]*m[15] + m[1]*m[14]*m[11] + m[2]*m[9]*m[15] - m[2]*m[13]*m[11] - m[3]*m[9]*m[14] + m[3]*m[13]*m[10]; 556 r[2] = m[1]*m[6]*m[15] - m[1]*m[14]*m[7] - m[2]*m[5]*m[15] + m[2]*m[13]*m[7] + m[3]*m[5]*m[14] - m[3]*m[13]*m[6]; 557 r[3] = -m[1]*m[6]*m[11] + m[1]*m[10]*m[7] + m[2]*m[5]*m[11] - m[2]*m[9]*m[7] - m[3]*m[5]*m[10] + m[3]*m[9]*m[6]; 558 559 r[4] = -m[4]*m[10]*m[15] + m[4]*m[14]*m[11] + m[6]*m[8]*m[15] - m[6]*m[12]*m[11] - m[7]*m[8]*m[14] + m[7]*m[12]*m[10]; 560 r[5] = m[0]*m[10]*m[15] - m[0]*m[14]*m[11] - m[2]*m[8]*m[15] + m[2]*m[12]*m[11] + m[3]*m[8]*m[14] - m[3]*m[12]*m[10]; 561 r[6] = -m[0]*m[6]*m[15] + m[0]*m[14]*m[7] + m[2]*m[4]*m[15] - m[2]*m[12]*m[7] - m[3]*m[4]*m[14] + m[3]*m[12]*m[6]; 562 r[7] = m[0]*m[6]*m[11] - m[0]*m[10]*m[7] - m[2]*m[4]*m[11] + m[2]*m[8]*m[7] + m[3]*m[4]*m[10] - m[3]*m[8]*m[6]; 563 564 r[8] = m[4]*m[9]*m[15] - m[4]*m[13]*m[11] - m[5]*m[8]*m[15] + m[5]*m[12]*m[11] + m[7]*m[8]*m[13] - m[7]*m[12]*m[9]; 565 r[9] = -m[0]*m[9]*m[15] + m[0]*m[13]*m[11] + m[1]*m[8]*m[15] - m[1]*m[12]*m[11] - m[3]*m[8]*m[13] + m[3]*m[12]*m[9]; 566 r[10] = m[0]*m[5]*m[15] - m[0]*m[13]*m[7] - m[1]*m[4]*m[15] + m[1]*m[12]*m[7] + m[3]*m[4]*m[13] - m[3]*m[12]*m[5]; 567 r[11] = -m[0]*m[5]*m[11] + m[0]*m[9]*m[7] + m[1]*m[4]*m[11] - m[1]*m[8]*m[7] - m[3]*m[4]*m[9] + m[3]*m[8]*m[5]; 568 569 r[12] = -m[4]*m[9]*m[14] + m[4]*m[13]*m[10] + m[5]*m[8]*m[14] - m[5]*m[12]*m[10] - m[6]*m[8]*m[13] + m[6]*m[12]*m[9]; 570 r[13] = m[0]*m[9]*m[14] - m[0]*m[13]*m[10] - m[1]*m[8]*m[14] + m[1]*m[12]*m[10] + m[2]*m[8]*m[13] - m[2]*m[12]*m[9]; 571 r[14] = -m[0]*m[5]*m[14] + m[0]*m[13]*m[6] + m[1]*m[4]*m[14] - m[1]*m[12]*m[6] - m[2]*m[4]*m[13] + m[2]*m[12]*m[5]; 572 r[15] = m[0]*m[5]*m[10] - m[0]*m[9]*m[6] - m[1]*m[4]*m[10] + m[1]*m[8]*m[6] + m[2]*m[4]*m[9] - m[2]*m[8]*m[5]; 573 574 var det = m[0]*r[0] + m[1]*r[4] + m[2]*r[8] + m[3]*r[12]; 575 for (var i = 0; i < 16; i++) r[i] /= det; 576 return result; 577 }, 578 multiply(left, result) { 579 result = result || new Matrix3D(); 580 var a = this.m, b = left.m, r = result.m; 581 582 r[0] = a[0] * b[0] + a[1] * b[4] + a[2] * b[8] + a[3] * b[12]; 583 r[1] = a[0] * b[1] + a[1] * b[5] + a[2] * b[9] + a[3] * b[13]; 584 r[2] = a[0] * b[2] + a[1] * b[6] + a[2] * b[10] + a[3] * b[14]; 585 r[3] = a[0] * b[3] + a[1] * b[7] + a[2] * b[11] + a[3] * b[15]; 586 587 r[4] = a[4] * b[0] + a[5] * b[4] + a[6] * b[8] + a[7] * b[12]; 588 r[5] = a[4] * b[1] + a[5] * b[5] + a[6] * b[9] + a[7] * b[13]; 589 r[6] = a[4] * b[2] + a[5] * b[6] + a[6] * b[10] + a[7] * b[14]; 590 r[7] = a[4] * b[3] + a[5] * b[7] + a[6] * b[11] + a[7] * b[15]; 591 592 r[8] = a[8] * b[0] + a[9] * b[4] + a[10] * b[8] + a[11] * b[12]; 593 r[9] = a[8] * b[1] + a[9] * b[5] + a[10] * b[9] + a[11] * b[13]; 594 r[10] = a[8] * b[2] + a[9] * b[6] + a[10] * b[10] + a[11] * b[14]; 595 r[11] = a[8] * b[3] + a[9] * b[7] + a[10] * b[11] + a[11] * b[15]; 596 597 r[12] = a[12] * b[0] + a[13] * b[4] + a[14] * b[8] + a[15] * b[12]; 598 r[13] = a[12] * b[1] + a[13] * b[5] + a[14] * b[9] + a[15] * b[13]; 599 r[14] = a[12] * b[2] + a[13] * b[6] + a[14] * b[10] + a[15] * b[14]; 600 r[15] = a[12] * b[3] + a[13] * b[7] + a[14] * b[11] + a[15] * b[15]; 601 602 return result; 603 }, 604 scale(x, y, z, result) { 605 result = result || new Matrix3D(); 606 var m = result.m; 607 608 m[0] = x; 609 m[1] = 0; 610 m[2] = 0; 611 m[3] = 0; 612 613 m[4] = 0; 614 m[5] = y; 615 m[6] = 0; 616 m[7] = 0; 617 618 m[8] = 0; 619 m[9] = 0; 620 m[10] = z; 621 m[11] = 0; 622 623 m[12] = 0; 624 m[13] = 0; 625 m[14] = 0; 626 m[15] = 1; 627 628 return result; 629 }, 630 rotate(a, x, y, z, result) { 631 result = result || new Matrix3D(); 632 var m = result.m; 633 634 var d = Math.sqrt(x*x + y*y + z*z); 635 a *= Math.PI / 180; x /= d; y /= d; z /= d; 636 var c = Math.cos(a), s = Math.sin(a), t = 1 - c; 637 638 m[0] = x * x * t + c; 639 m[1] = x * y * t - z * s; 640 m[2] = x * z * t + y * s; 641 m[3] = 0; 642 643 m[4] = y * x * t + z * s; 644 m[5] = y * y * t + c; 645 m[6] = y * z * t - x * s; 646 m[7] = 0; 647 648 m[8] = z * x * t - y * s; 649 m[9] = z * y * t + x * s; 650 m[10] = z * z * t + c; 651 m[11] = 0; 652 653 m[12] = 0; 654 m[13] = 0; 655 m[14] = 0; 656 m[15] = 1; 657 658 return result; 659 }, 660 swap(result) { 661 result = result || new Matrix3D(); 662 for (var x = 0; x < 16; x++) 663 result.m[x] = this.m[Math.floor(x/4) + (x%4)*4]; 664 665 return result; 666 } 667 }; 668 669 670 function test3D() 671 { 672 var m = new DOMMatrix() 673 var m2 = new Matrix3D(); 674 675 m.translateSelf(2,3,4).scaleSelf(1.2, 2.3, 3.4, 0, 0, 0); 676 m2 = m2.multiply(m2.translate(2,3,4)).multiply(m2.scale(1.2, 2.3, 3.4)).swap(); 677 678 ok(CompareMatrix(m2, m), "translate + scale in 3d didn't match, expected: " + formatMatrix(m2.m) + ", got: " + formatMatrix(m)); 679 680 m.invertSelf(); 681 m2 = new Matrix3D(); 682 m2 = m2.multiply(m2.translate(2,3,4)).multiply(m2.scale(1.2, 2.3, 3.4)); 683 m2 = m2.inverse(m2).swap(); 684 ok(CompareMatrix(m2, m), "translate + scale in inverted 3d didn't match, expected: " + formatMatrix(m2.m) + ", got: " + formatMatrix(m)); 685 } 686 687 function testParsing() 688 { 689 var m = new DOMMatrix("translate(10px, 20px) scale(.5, 2) rotate(45deg)"); 690 var m2 = new DOMMatrix(); 691 m2.translateSelf(10, 20).scaleSelf(.5,2).rotateSelf(45); 692 ok(CompareDOMMatrix(m2, m), "string parsing didn't match"); 693 694 m = new DOMMatrix(); 695 m.setMatrixValue("translate(10px, 20px) scale(.5, 2) rotate(45deg)"); 696 ok(CompareDOMMatrix(m2, m), "string parsing didn't match"); 697 } 698 699 700 function testStringify() { 701 var m = new DOMMatrix(); 702 var s = "" + m; 703 ok(s == "matrix" + formatMatrix(m), "stringifier 1 produced wrong result: " + s); 704 m.a = 100; 705 s = "" + m; 706 ok(s == "matrix" + formatMatrix(m), "stringifier 2 produced wrong result: " + s); 707 m.m43 = 200; 708 s = "" + m; 709 ok(s == "matrix3d" + formatMatrix(m), "stringifier 3 produced wrong result:" + s); 710 } 711 712 window.addEventListener("load", main); 713 714 </script> 715 </pre> 716 </body> 717 </html>