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