xref: /aosp_15_r20/external/skia/modules/canvaskit/tests/matrix_test.js (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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