1cb93a386Sopenharmony_cidescribe('CanvasKit\'s Matrix Helpers', () => { 2cb93a386Sopenharmony_ci 3cb93a386Sopenharmony_ci beforeEach(async () => { 4cb93a386Sopenharmony_ci await LoadCanvasKit; 5cb93a386Sopenharmony_ci }); 6cb93a386Sopenharmony_ci 7cb93a386Sopenharmony_ci const expectArrayCloseTo = (a, b, precision) => { 8cb93a386Sopenharmony_ci precision = precision || 14; // digits of precision in base 10 9cb93a386Sopenharmony_ci expect(a.length).toEqual(b.length); 10cb93a386Sopenharmony_ci for (let i=0; i<a.length; i++) { 11cb93a386Sopenharmony_ci expect(a[i]).toBeCloseTo(b[i], precision); 12cb93a386Sopenharmony_ci } 13cb93a386Sopenharmony_ci }; 14cb93a386Sopenharmony_ci 15cb93a386Sopenharmony_ci describe('3x3 matrices', () => { 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ci it('can make a translated 3x3 matrix', () => { 18cb93a386Sopenharmony_ci expectArrayCloseTo( 19cb93a386Sopenharmony_ci CanvasKit.Matrix.translated(5, -1), 20cb93a386Sopenharmony_ci [1, 0, 5, 21cb93a386Sopenharmony_ci 0, 1, -1, 22cb93a386Sopenharmony_ci 0, 0, 1]); 23cb93a386Sopenharmony_ci }); 24cb93a386Sopenharmony_ci 25cb93a386Sopenharmony_ci it('can make a scaled 3x3 matrix', () => { 26cb93a386Sopenharmony_ci expectArrayCloseTo( 27cb93a386Sopenharmony_ci CanvasKit.Matrix.scaled(2, 3), 28cb93a386Sopenharmony_ci [2, 0, 0, 29cb93a386Sopenharmony_ci 0, 3, 0, 30cb93a386Sopenharmony_ci 0, 0, 1]); 31cb93a386Sopenharmony_ci }); 32cb93a386Sopenharmony_ci 33cb93a386Sopenharmony_ci it('can make a rotated 3x3 matrix', () => { 34cb93a386Sopenharmony_ci expectArrayCloseTo( 35cb93a386Sopenharmony_ci CanvasKit.Matrix.rotated(Math.PI, 9, 9), 36cb93a386Sopenharmony_ci [-1, 0, 18, 37cb93a386Sopenharmony_ci 0, -1, 18, 38cb93a386Sopenharmony_ci 0, 0, 1]); 39cb93a386Sopenharmony_ci }); 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci it('can make a skewed 3x3 matrix', () => { 42cb93a386Sopenharmony_ci expectArrayCloseTo( 43cb93a386Sopenharmony_ci CanvasKit.Matrix.skewed(4, 3, 2, 1), 44cb93a386Sopenharmony_ci [1, 4, -8, 45cb93a386Sopenharmony_ci 3, 1, -3, 46cb93a386Sopenharmony_ci 0, 0, 1]); 47cb93a386Sopenharmony_ci }); 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_ci it('can multiply 3x3 matrices', () => { 50cb93a386Sopenharmony_ci const a = [ 51cb93a386Sopenharmony_ci 0.1, 0.2, 0.3, 52cb93a386Sopenharmony_ci 0.0, 0.6, 0.7, 53cb93a386Sopenharmony_ci 0.9, -0.9, -0.8, 54cb93a386Sopenharmony_ci ]; 55cb93a386Sopenharmony_ci const b = [ 56cb93a386Sopenharmony_ci 2.0, 3.0, 4.0, 57cb93a386Sopenharmony_ci -3.0, -4.0, -5.0, 58cb93a386Sopenharmony_ci 7.0, 8.0, 9.0, 59cb93a386Sopenharmony_ci ]; 60cb93a386Sopenharmony_ci const expected = [ 61cb93a386Sopenharmony_ci 1.7, 1.9, 2.1, 62cb93a386Sopenharmony_ci 3.1, 3.2, 3.3, 63cb93a386Sopenharmony_ci -1.1, -0.1, 0.9, 64cb93a386Sopenharmony_ci ]; 65cb93a386Sopenharmony_ci expectArrayCloseTo( 66cb93a386Sopenharmony_ci CanvasKit.Matrix.multiply(a, b), 67cb93a386Sopenharmony_ci expected); 68cb93a386Sopenharmony_ci }); 69cb93a386Sopenharmony_ci 70cb93a386Sopenharmony_ci it('satisfies the inverse rule for 3x3 matrics', () => { 71cb93a386Sopenharmony_ci // a matrix times its inverse is the identity matrix. 72cb93a386Sopenharmony_ci const a = [ 73cb93a386Sopenharmony_ci 0.1, 0.2, 0.3, 74cb93a386Sopenharmony_ci 0.0, 0.6, 0.7, 75cb93a386Sopenharmony_ci 0.9, -0.9, -0.8, 76cb93a386Sopenharmony_ci ]; 77cb93a386Sopenharmony_ci const b = CanvasKit.Matrix.invert(a); 78cb93a386Sopenharmony_ci expectArrayCloseTo( 79cb93a386Sopenharmony_ci CanvasKit.Matrix.multiply(a, b), 80cb93a386Sopenharmony_ci CanvasKit.Matrix.identity()); 81cb93a386Sopenharmony_ci }); 82cb93a386Sopenharmony_ci 83cb93a386Sopenharmony_ci it('maps 2D points correctly with a 3x3 matrix', () => { 84cb93a386Sopenharmony_ci const a = [ 85cb93a386Sopenharmony_ci 3, 0, -4, 86cb93a386Sopenharmony_ci 0, 2, 4, 87cb93a386Sopenharmony_ci 0, 0, 1, 88cb93a386Sopenharmony_ci ]; 89cb93a386Sopenharmony_ci const points = [ 90cb93a386Sopenharmony_ci 0, 0, 91cb93a386Sopenharmony_ci 1, 1, 92cb93a386Sopenharmony_ci ]; 93cb93a386Sopenharmony_ci const expected = [ 94cb93a386Sopenharmony_ci -4, 4, 95cb93a386Sopenharmony_ci -1, 6, 96cb93a386Sopenharmony_ci ]; 97cb93a386Sopenharmony_ci expectArrayCloseTo( 98cb93a386Sopenharmony_ci CanvasKit.Matrix.mapPoints(a, points), 99cb93a386Sopenharmony_ci expected); 100cb93a386Sopenharmony_ci }); 101cb93a386Sopenharmony_ci 102cb93a386Sopenharmony_ci }); // describe 3x3 103cb93a386Sopenharmony_ci describe('4x4 matrices', () => { 104cb93a386Sopenharmony_ci 105cb93a386Sopenharmony_ci it('can make a translated 4x4 matrix', () => { 106cb93a386Sopenharmony_ci expectArrayCloseTo( 107cb93a386Sopenharmony_ci CanvasKit.M44.translated([5, 6, 7]), 108cb93a386Sopenharmony_ci [1, 0, 0, 5, 109cb93a386Sopenharmony_ci 0, 1, 0, 6, 110cb93a386Sopenharmony_ci 0, 0, 1, 7, 111cb93a386Sopenharmony_ci 0, 0, 0, 1]); 112cb93a386Sopenharmony_ci }); 113cb93a386Sopenharmony_ci 114cb93a386Sopenharmony_ci it('can make a scaled 4x4 matrix', () => { 115cb93a386Sopenharmony_ci expectArrayCloseTo( 116cb93a386Sopenharmony_ci CanvasKit.M44.scaled([5, 6, 7]), 117cb93a386Sopenharmony_ci [5, 0, 0, 0, 118cb93a386Sopenharmony_ci 0, 6, 0, 0, 119cb93a386Sopenharmony_ci 0, 0, 7, 0, 120cb93a386Sopenharmony_ci 0, 0, 0, 1]); 121cb93a386Sopenharmony_ci }); 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_ci it('can make a rotated 4x4 matrix', () => { 124cb93a386Sopenharmony_ci expectArrayCloseTo( 125cb93a386Sopenharmony_ci CanvasKit.M44.rotated([1,1,1], Math.PI), 126cb93a386Sopenharmony_ci [-1/3, 2/3, 2/3, 0, 127cb93a386Sopenharmony_ci 2/3, -1/3, 2/3, 0, 128cb93a386Sopenharmony_ci 2/3, 2/3, -1/3, 0, 129cb93a386Sopenharmony_ci 0, 0, 0, 1]); 130cb93a386Sopenharmony_ci }); 131cb93a386Sopenharmony_ci 132cb93a386Sopenharmony_ci it('can make a 4x4 matrix looking from eye to center', () => { 133cb93a386Sopenharmony_ci eye = [1, 0, 0]; 134cb93a386Sopenharmony_ci center = [1, 0, 1]; 135cb93a386Sopenharmony_ci up = [0, 1, 0] 136cb93a386Sopenharmony_ci expectArrayCloseTo( 137cb93a386Sopenharmony_ci CanvasKit.M44.lookat(eye, center, up), 138cb93a386Sopenharmony_ci [-1, 0, 0, 1, 139cb93a386Sopenharmony_ci 0, 1, 0, 0, 140cb93a386Sopenharmony_ci 0, 0, -1, 0, 141cb93a386Sopenharmony_ci 0, 0, 0, 1]); 142cb93a386Sopenharmony_ci }); 143cb93a386Sopenharmony_ci 144cb93a386Sopenharmony_ci it('can make a 4x4 prespective matrix', () => { 145cb93a386Sopenharmony_ci expectArrayCloseTo( 146cb93a386Sopenharmony_ci CanvasKit.M44.perspective(2, 10, Math.PI/2), 147cb93a386Sopenharmony_ci [1, 0, 0, 0, 148cb93a386Sopenharmony_ci 0, 1, 0, 0, 149cb93a386Sopenharmony_ci 0, 0, 1.5, 5, 150cb93a386Sopenharmony_ci 0, 0, -1, 1]); 151cb93a386Sopenharmony_ci }); 152cb93a386Sopenharmony_ci 153cb93a386Sopenharmony_ci it('can multiply 4x4 matrices', () => { 154cb93a386Sopenharmony_ci const a = [ 155cb93a386Sopenharmony_ci 0.1, 0.2, 0.3, 0.4, 156cb93a386Sopenharmony_ci 0.0, 0.6, 0.7, 0.8, 157cb93a386Sopenharmony_ci 0.9, -0.9, -0.8, -0.7, 158cb93a386Sopenharmony_ci -0.6, -0.5, -0.4, -0.3, 159cb93a386Sopenharmony_ci ]; 160cb93a386Sopenharmony_ci const b = [ 161cb93a386Sopenharmony_ci 2.0, 3.0, 4.0, 5.0, 162cb93a386Sopenharmony_ci -3.0, -4.0, -5.0, -6.0, 163cb93a386Sopenharmony_ci 7.0, 8.0, 9.0, 10.0, 164cb93a386Sopenharmony_ci -4.0, -3.0, -2.0, -1.0, 165cb93a386Sopenharmony_ci ]; 166cb93a386Sopenharmony_ci const expected = [ 167cb93a386Sopenharmony_ci 0.1, 0.7, 1.3, 1.9, 168cb93a386Sopenharmony_ci -0.1, 0.8, 1.7, 2.6, 169cb93a386Sopenharmony_ci 1.7, 2.0, 2.3, 2.6, 170cb93a386Sopenharmony_ci -1.3, -2.1, -2.9, -3.7, 171cb93a386Sopenharmony_ci ]; 172cb93a386Sopenharmony_ci expectArrayCloseTo( 173cb93a386Sopenharmony_ci CanvasKit.M44.multiply(a, b), 174cb93a386Sopenharmony_ci expected); 175cb93a386Sopenharmony_ci }); 176cb93a386Sopenharmony_ci 177cb93a386Sopenharmony_ci it('satisfies the identity rule for 4x4 matrices', () => { 178cb93a386Sopenharmony_ci const a = [ 179cb93a386Sopenharmony_ci 0.1, 0.2, 0.3, 0.4, 180cb93a386Sopenharmony_ci 0.0, 0.6, 0.7, 0.8, 181cb93a386Sopenharmony_ci 0.9, 0.9, -0.8, -0.7, 182cb93a386Sopenharmony_ci -0.6, -0.5, -0.4, -0.3, 183cb93a386Sopenharmony_ci ]; 184cb93a386Sopenharmony_ci const b = CanvasKit.M44.invert(a) 185cb93a386Sopenharmony_ci expectArrayCloseTo( 186cb93a386Sopenharmony_ci CanvasKit.M44.multiply(a, b), 187cb93a386Sopenharmony_ci CanvasKit.M44.identity()); 188cb93a386Sopenharmony_ci }); 189cb93a386Sopenharmony_ci 190cb93a386Sopenharmony_ci it('can create a camera setup matrix', () => { 191cb93a386Sopenharmony_ci const camAngle = Math.PI / 12; 192cb93a386Sopenharmony_ci const cam = { 193cb93a386Sopenharmony_ci 'eye' : [0, 0, 1 / Math.tan(camAngle/2) - 1], 194cb93a386Sopenharmony_ci 'coa' : [0, 0, 0], 195cb93a386Sopenharmony_ci 'up' : [0, 1, 0], 196cb93a386Sopenharmony_ci 'near' : 0.02, 197cb93a386Sopenharmony_ci 'far' : 4, 198cb93a386Sopenharmony_ci 'angle': camAngle, 199cb93a386Sopenharmony_ci }; 200cb93a386Sopenharmony_ci const mat = CanvasKit.M44.setupCamera(CanvasKit.LTRBRect(0, 0, 200, 200), 200, cam); 201cb93a386Sopenharmony_ci // these values came from an invocation of setupCamera visually inspected. 202cb93a386Sopenharmony_ci const expected = [ 203cb93a386Sopenharmony_ci 7.595754, 0, -0.5, 0, 204cb93a386Sopenharmony_ci 0, 7.595754, -0.5, 0, 205cb93a386Sopenharmony_ci 0, 0, 1.010050, -1324.368418, 206cb93a386Sopenharmony_ci 0, 0, -0.005, 7.595754]; 207cb93a386Sopenharmony_ci expectArrayCloseTo(mat, expected, 5); 208cb93a386Sopenharmony_ci }); 209cb93a386Sopenharmony_ci }); // describe 4x4 210cb93a386Sopenharmony_ci}); 211