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