1/* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17import {Point} from './point'; 18import {Point3D} from './point3d'; 19import {Rect} from './rect'; 20import {Region} from './region'; 21 22/** 23 * These values correspond to the values from the gui::Transform class in the 24 * platform, defined in: 25 * frameworks/native/libs/ui/include/ui/Transform.h 26 * The values are listed in row-major order: 27 * [ dsdx, dtdx, tx ] 28 * [ dtdy, dsdy, ty ] 29 * [ 0, 0, 1 ] 30 */ 31export class TransformMatrix { 32 constructor( 33 readonly dsdx: number, 34 readonly dtdx: number, 35 readonly tx: number, 36 readonly dtdy: number, 37 readonly dsdy: number, 38 readonly ty: number, 39 ) {} 40 41 static from( 42 m: { 43 dsdx?: number; 44 dtdx?: number; 45 tx?: number; 46 dtdy?: number; 47 dsdy?: number; 48 ty?: number; 49 } = {}, 50 fallback: TransformMatrix = IDENTITY_MATRIX, 51 ): TransformMatrix { 52 return new TransformMatrix( 53 m.dsdx ?? fallback.dsdx, 54 m.dtdx ?? fallback.dtdx, 55 m.tx ?? fallback.tx, 56 m.dtdy ?? fallback.dtdy, 57 m.dsdy ?? fallback.dsdy, 58 m.ty ?? fallback.ty, 59 ); 60 } 61 62 isValid(): boolean { 63 return this.dsdx * this.dsdy !== this.dtdx * this.dtdy; 64 } 65 66 transformPoint(point: Point): Point { 67 return { 68 x: this.dsdx * point.x + this.dtdx * point.y + this.tx, 69 y: this.dtdy * point.x + this.dsdy * point.y + this.ty, 70 }; 71 } 72 73 transformPoint3D(point: Point3D): Point3D { 74 const p = this.transformPoint(point); 75 return new Point3D(p.x, p.y, point.z); 76 } 77 78 transformRect(r: Rect): Rect { 79 const ltPrime = this.transformPoint({x: r.x, y: r.y}); 80 const rbPrime = this.transformPoint({x: r.x + r.w, y: r.y + r.h}); 81 const x = Math.min(ltPrime.x, rbPrime.x); 82 const y = Math.min(ltPrime.y, rbPrime.y); 83 return new Rect( 84 x, 85 y, 86 Math.max(ltPrime.x, rbPrime.x) - x, 87 Math.max(ltPrime.y, rbPrime.y) - y, 88 ); 89 } 90 91 transformRegion(region: Region): Region { 92 return new Region(region.rects.map((rect) => this.transformRect(rect))); 93 } 94 95 inverse(): TransformMatrix { 96 const ident = 1.0 / this.det(); 97 const result = { 98 dsdx: this.dsdy * ident, 99 dtdx: -this.dtdx * ident, 100 tx: 0, 101 dsdy: this.dsdx * ident, 102 dtdy: -this.dtdy * ident, 103 ty: 0, 104 }; 105 const t = TransformMatrix.from(result).transformPoint({ 106 x: -this.tx, 107 y: -this.ty, 108 }); 109 result.tx = t.x; 110 result.ty = t.y; 111 return TransformMatrix.from(result); 112 } 113 114 addTy(ty: number): TransformMatrix { 115 return new TransformMatrix( 116 this.dsdx, 117 this.dtdx, 118 this.tx, 119 this.dtdy, 120 this.dsdy, 121 this.ty + ty, 122 ); 123 } 124 125 isEqual(other: TransformMatrix): boolean { 126 return ( 127 this.dsdx === other.dsdx && 128 this.dtdx === other.dtdx && 129 this.tx === other.tx && 130 this.dtdy === other.dtdy && 131 this.dsdy === other.dsdy && 132 this.ty === other.ty 133 ); 134 } 135 136 private det(): number { 137 return this.dsdx * this.dsdy - this.dtdx * this.dtdy; 138 } 139} 140 141/** 142 * The identity matrix, which has no effect on any point or rect. 143 */ 144export const IDENTITY_MATRIX = new TransformMatrix(1, 0, 0, 0, 1, 0); 145