@leafer/math
Advanced tools
+2
-2
| { | ||
| "name": "@leafer/math", | ||
| "version": "1.0.0-alpha.21", | ||
| "version": "1.0.0-alpha.23", | ||
| "description": "@leafer/math", | ||
@@ -22,4 +22,4 @@ "author": "Chao (Leafer) Wan", | ||
| "devDependencies": { | ||
| "@leafer/interface": "1.0.0-alpha.21" | ||
| "@leafer/interface": "1.0.0-alpha.23" | ||
| } | ||
| } |
+4
-4
@@ -35,4 +35,4 @@ import { IBounds, IBoundsData, IMatrixData, IPointData, IBoundsDataHandle, IObject, IMatrix, IRadiusPointData } from '@leafer/interface' | ||
| public toWorld(matrix: IMatrixData, to: IBoundsData): IBounds { | ||
| B.toWorld(this, matrix, to) | ||
| public toOuterOf(matrix: IMatrixData, to?: IBoundsData): IBounds { | ||
| B.toOuterOf(this, matrix, to) | ||
| return this | ||
@@ -124,6 +124,6 @@ } | ||
| public empty(): void { | ||
| B.empty(this) | ||
| public reset(): void { | ||
| B.reset(this) | ||
| } | ||
| } |
+19
-29
@@ -9,3 +9,3 @@ import { IPointData, IBoundsData, IMatrixData, IBoundsDataHandle, IObject, IMatrix, IOffsetBoundsData, IRadiusPointData } from '@leafer/interface' | ||
| const { tempPointBounds, setPoint, addPoint, toBounds } = TB | ||
| const { toWorldPoint } = M | ||
| const { toOuterPoint } = M | ||
@@ -72,15 +72,15 @@ let right: number, bottom: number, boundsRight: number, boundsBottom: number | ||
| tempToWorld(t: IBoundsData, matrix: IMatrixData): IBoundsData { | ||
| tempToOuterOf(t: IBoundsData, matrix: IMatrixData): IBoundsData { | ||
| B.copy(B.tempBounds, t) | ||
| B.toWorld(B.tempBounds, matrix) | ||
| B.toOuterOf(B.tempBounds, matrix) | ||
| return B.tempBounds | ||
| }, | ||
| getWorld(t: IBoundsData, matrix: IMatrixData): IBoundsData { | ||
| getOuterOf(t: IBoundsData, matrix: IMatrixData): IBoundsData { | ||
| t = { ...t } | ||
| B.toWorld(t, matrix) | ||
| B.toOuterOf(t, matrix) | ||
| return t | ||
| }, | ||
| toWorld(t: IBoundsData, matrix: IMatrixData, to?: IBoundsData): void { | ||
| toOuterOf(t: IBoundsData, matrix: IMatrixData, to?: IBoundsData): void { | ||
@@ -101,3 +101,3 @@ to || (to = t) | ||
| toWorldPoint(matrix, point, toPoint) | ||
| toOuterPoint(matrix, point, toPoint) | ||
| setPoint(tempPointBounds, toPoint.x, toPoint.y) | ||
@@ -107,3 +107,3 @@ | ||
| toWorldPoint(matrix, point, toPoint) | ||
| toOuterPoint(matrix, point, toPoint) | ||
| addPoint(tempPointBounds, toPoint.x, toPoint.y) | ||
@@ -113,3 +113,3 @@ | ||
| toWorldPoint(matrix, point, toPoint) | ||
| toOuterPoint(matrix, point, toPoint) | ||
| addPoint(tempPointBounds, toPoint.x, toPoint.y) | ||
@@ -119,3 +119,3 @@ | ||
| toWorldPoint(matrix, point, toPoint) | ||
| toOuterPoint(matrix, point, toPoint) | ||
| addPoint(tempPointBounds, toPoint.x, toPoint.y) | ||
@@ -127,9 +127,2 @@ | ||
| /**toLocal(t: IBoundsData, matrix: IMatrixData): void { | ||
| t.x = (t.x - matrix.e) / matrix.a | ||
| t.y = (t.y - matrix.f) / matrix.d | ||
| t.width /= matrix.a | ||
| t.height /= matrix.d | ||
| },*/ | ||
| getFitMatrix(t: IBoundsData, put: IBoundsData): IMatrix { | ||
@@ -186,3 +179,3 @@ const scale = Math.min(1, Math.min(t.width / put.width, t.height / put.height)) | ||
| if (!list.length) { | ||
| B.empty(t) | ||
| B.reset(t) | ||
| return | ||
@@ -194,3 +187,3 @@ } | ||
| bounds = boundsDataHandle ? boundsDataHandle(list[i]) : list[i] as IBoundsData | ||
| if (bounds.width || bounds.height) { // 必须有效的bounds | ||
| if (bounds && (bounds.width || bounds.height)) { // 必须有效的bounds | ||
| if (first) { | ||
@@ -214,3 +207,3 @@ first = false | ||
| hitRadiusPoint(t: IBoundsData, point: IRadiusPointData, pointMatrix?: IMatrixData): boolean { | ||
| if (pointMatrix) point = P.tempToLocalRadiusPoint(point, pointMatrix) | ||
| if (pointMatrix) point = P.tempToInnerRadiusPointOf(point, pointMatrix) | ||
| return (point.x >= t.x - point.radiusX && point.x <= t.x + t.width + point.radiusX) && (point.y >= t.y - point.radiusY && point.y <= t.y + t.height + point.radiusY) | ||
@@ -220,3 +213,3 @@ }, | ||
| hitPoint(t: IBoundsData, point: IPointData, pointMatrix?: IMatrixData): boolean { | ||
| if (pointMatrix) point = P.tempToLocal(point, pointMatrix) | ||
| if (pointMatrix) point = P.tempToInnerOf(point, pointMatrix) | ||
| return (point.x >= t.x && point.x <= t.x + t.width) && (point.y >= t.y && point.y <= t.y + t.height) | ||
@@ -227,3 +220,3 @@ }, | ||
| hit(t: IBoundsData, other: IBoundsData, otherMatrix?: IMatrixData): boolean { | ||
| if (otherMatrix) other = B.tempToWorld(other, otherMatrix) | ||
| if (otherMatrix) other = B.tempToOuterOf(other, otherMatrix) | ||
| return !((t.y + t.height < other.y) || (other.y + other.height < t.y) || (t.x + t.width < other.x) || (other.x + other.width < t.x)) | ||
@@ -233,3 +226,3 @@ }, | ||
| includes(t: IBoundsData, other: IBoundsData, otherMatrix?: IMatrixData): boolean { | ||
| if (otherMatrix) other = B.tempToWorld(other, otherMatrix) | ||
| if (otherMatrix) other = B.tempToOuterOf(other, otherMatrix) | ||
| return (t.x <= other.x) && (t.y <= other.y) && (t.x + t.width >= other.x + other.width) && (t.y + t.height >= other.y + other.height) | ||
@@ -239,3 +232,3 @@ }, | ||
| getIntersectData(t: IBoundsData, other: IBoundsData, otherMatrix?: IMatrixData): IBoundsData { | ||
| if (otherMatrix) other = B.tempToWorld(other, otherMatrix) | ||
| if (otherMatrix) other = B.tempToOuterOf(other, otherMatrix) | ||
| let { x, y, width, height } = other | ||
@@ -271,7 +264,4 @@ | ||
| empty(bounds: IBoundsData): void { | ||
| bounds.x = 0 | ||
| bounds.y = 0 | ||
| bounds.width = 0 | ||
| bounds.height = 0 | ||
| reset(t: IBoundsData): void { | ||
| B.set(t) | ||
| } | ||
@@ -278,0 +268,0 @@ } |
+54
-11
@@ -1,2 +0,2 @@ | ||
| import { IMatrix, IMatrixData, IPointData } from '@leafer/interface' | ||
| import { IMatrix, IMatrixData, IPointData, IMatrixDecompositionData } from '@leafer/interface' | ||
| import { MatrixHelper as M } from './MatrixHelper' | ||
@@ -33,7 +33,11 @@ | ||
| public translate(x: number, y: number): IMatrix { | ||
| this.e += x | ||
| this.f += y | ||
| M.translate(this, x, y) | ||
| return this | ||
| } | ||
| public translateInner(x: number, y: number): IMatrix { | ||
| M.translateInner(this, x, y) | ||
| return this | ||
| } | ||
| public scale(x: number, y?: number): IMatrix { | ||
@@ -44,2 +48,11 @@ M.scale(this, x, y) | ||
| public scaleOf(center: IPointData, x: number, y?: number): IMatrix { | ||
| M.scaleOf(this, center, x, y) | ||
| return this | ||
| } | ||
| public scaleOfInner(center: IPointData, x: number, y?: number): IMatrix { | ||
| M.scaleOfInner(this, center, x, y) | ||
| return this | ||
| } | ||
| public rotate(angle: number): IMatrix { | ||
@@ -50,8 +63,34 @@ M.rotate(this, angle) | ||
| public rotateOf(center: IPointData, angle: number): IMatrix { | ||
| M.rotateOf(this, center, angle) | ||
| return this | ||
| } | ||
| public times(matrix: IMatrixData): IMatrix { | ||
| M.times(this, matrix) | ||
| public rotateOfInner(center: IPointData, angle: number): IMatrix { | ||
| M.rotateOfInner(this, center, angle) | ||
| return this | ||
| } | ||
| public skew(x: number, y?: number): IMatrix { | ||
| M.skew(this, x, y) | ||
| return this | ||
| } | ||
| public skewOf(center: IPointData, x: number, y?: number): IMatrix { | ||
| M.skewOf(this, center, x, y) | ||
| return this | ||
| } | ||
| public skewOfInner(center: IPointData, x: number, y?: number): IMatrix { | ||
| M.skewOfInner(this, center, x, y) | ||
| return this | ||
| } | ||
| public multiply(matrix: IMatrixData): IMatrix { | ||
| M.multiply(this, matrix) | ||
| return this | ||
| } | ||
| public divide(matrix: IMatrixData): IMatrix { | ||
@@ -68,15 +107,19 @@ M.divide(this, matrix) | ||
| public toWorldPoint(local: IPointData, to?: IPointData): void { | ||
| M.toWorldPoint(this, local, to) | ||
| public toOuterPoint(inner: IPointData, to?: IPointData): void { | ||
| M.toOuterPoint(this, inner, to) | ||
| } | ||
| public toLocalPoint(world: IPointData, to?: IPointData): void { | ||
| M.toLocalPoint(this, world, to) | ||
| public toInnerPoint(outer: IPointData, to?: IPointData): void { | ||
| M.toInnerPoint(this, outer, to) | ||
| } | ||
| public decompose(): IMatrixDecompositionData { | ||
| return M.decompose(this) | ||
| } | ||
| public empty(): void { | ||
| M.empty(this) | ||
| public reset(): void { | ||
| M.reset(this) | ||
| } | ||
| } |
+131
-37
@@ -1,10 +0,15 @@ | ||
| import { IMatrix, IMatrixData, IPointData } from '@leafer/interface' | ||
| import { IMatrix, IMatrixData, IPointData, IMatrixDecompositionData } from '@leafer/interface' | ||
| import { OneRadian } from './MathHelper' | ||
| const { sin, cos } = Math | ||
| const { sin, cos, acos, atan, sqrt, PI } = Math | ||
| const tempPoint = {} as IPointData | ||
| function get(): IMatrixData { | ||
| return { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 } | ||
| } | ||
| export const MatrixHelper = { | ||
| defaultMatrix: { a: 1, b: 0, c: 0, d: 1, e: 0, f: 0 } as IMatrixData, | ||
| defaultMatrix: get(), | ||
@@ -22,2 +27,4 @@ tempMatrix: {} as IMatrixData, | ||
| get, | ||
| copy(t: IMatrixData, matrix: IMatrixData): void { | ||
@@ -32,2 +39,3 @@ t.a = matrix.a | ||
| translate(t: IMatrixData, x: number, y: number): void { | ||
@@ -38,2 +46,8 @@ t.e += x | ||
| translateInner(t: IMatrixData, x: number, y: number): void { | ||
| t.e += t.a * x + t.c * y | ||
| t.f += t.b * x + t.d * y | ||
| }, | ||
| scale(t: IMatrixData, x: number, y: number = x): void { | ||
@@ -44,12 +58,22 @@ t.a *= x | ||
| t.b *= y | ||
| t.e *= x | ||
| t.f *= y | ||
| }, | ||
| scaleOf(t: IMatrixData, center: IPointData, x: number, y: number = x): void { | ||
| M.toInnerPoint(t, center, tempPoint) | ||
| M.scaleOfInner(t, tempPoint, x, y) | ||
| }, | ||
| scaleOfInner(t: IMatrixData, center: IPointData, x: number, y: number = x): void { | ||
| M.translateInner(t, center.x, center.y) | ||
| M.scale(t, x, y) | ||
| M.translateInner(t, -center.x, -center.y) | ||
| }, | ||
| rotate(t: IMatrixData, angle: number): void { | ||
| const rotation = angle * OneRadian | ||
| const cosR = cos(rotation) | ||
| const sinR = sin(rotation) | ||
| angle *= OneRadian | ||
| const cosR = cos(angle) | ||
| const sinR = sin(angle) | ||
| const { a, b, c, d, e, f } = t | ||
| const { a, b, c, d } = t | ||
| t.a = (a * cosR) - (b * sinR) | ||
@@ -59,19 +83,55 @@ t.b = (a * sinR) + (b * cosR) | ||
| t.d = (c * sinR) + (d * cosR) | ||
| t.e = (e * cosR) - (f * sinR) | ||
| t.f = (e * sinR) + (f * cosR) | ||
| }, | ||
| times(t: IMatrixData, matrix: IMatrixData): void { | ||
| rotateOf(t: IMatrixData, center: IPointData, angle: number): void { | ||
| M.toInnerPoint(t, center, tempPoint) | ||
| M.rotateOfInner(t, tempPoint, angle) | ||
| }, | ||
| rotateOfInner(t: IMatrixData, center: IPointData, angle: number): void { | ||
| M.translateInner(t, center.x, center.y) | ||
| M.rotate(t, angle) | ||
| M.translateInner(t, -center.x, -center.y) | ||
| }, | ||
| skew(t: IMatrixData, x: number, y?: number): void { | ||
| const { a, b, c, d } = t | ||
| if (y) { | ||
| y *= OneRadian | ||
| t.a = a + c * y | ||
| t.b = b + d * y | ||
| } | ||
| if (x) { | ||
| x *= OneRadian | ||
| t.c = c + a * x | ||
| t.d = d + b * x | ||
| } | ||
| }, | ||
| skewOf(t: IMatrixData, center: IPointData, x: number, y?: number): void { | ||
| M.toInnerPoint(t, center, tempPoint) | ||
| M.skewOfInner(t, tempPoint, x, y) | ||
| }, | ||
| skewOfInner(t: IMatrixData, center: IPointData, x: number, y?: number): void { | ||
| M.translateInner(t, center.x, center.y) | ||
| M.skew(t, x, y) | ||
| M.translateInner(t, -center.x, -center.y) | ||
| }, | ||
| multiply(t: IMatrixData, matrix: IMatrixData): void { | ||
| const { a, b, c, d, e, f } = t | ||
| t.a = (matrix.a * a) + (matrix.b * c) | ||
| t.b = (matrix.a * b) + (matrix.b * d) | ||
| t.c = (matrix.c * a) + (matrix.d * c) | ||
| t.d = (matrix.c * b) + (matrix.d * d) | ||
| t.e = (matrix.e * a) + (matrix.f * c) + e | ||
| t.f = (matrix.e * b) + (matrix.f * d) + f | ||
| t.a = matrix.a * a + matrix.b * c | ||
| t.b = matrix.a * b + matrix.b * d | ||
| t.c = matrix.c * a + matrix.d * c | ||
| t.d = matrix.c * b + matrix.d * d | ||
| t.e = matrix.e * a + matrix.f * c + e | ||
| t.f = matrix.e * b + matrix.f * d + f | ||
| }, | ||
| divide(t: IMatrixData, matrix: IMatrixData): void { | ||
| M.times(t, M.tempInvert(matrix)) | ||
| M.multiply(t, M.tempInvert(matrix)) | ||
| }, | ||
@@ -97,22 +157,28 @@ | ||
| toWorldPoint(t: IMatrixData, local: IPointData, to?: IPointData): void { | ||
| const { x, y } = local | ||
| // world | ||
| to || (to = local) | ||
| to.x = (x * t.a) + (y * t.c) + t.e | ||
| to.y = (x * t.b) + (y * t.d) + t.f | ||
| toOuterPoint(t: IMatrixData, inner: IPointData, to?: IPointData, isMovePoint?: boolean): void { | ||
| const { x, y } = inner | ||
| // outer | ||
| to || (to = inner) | ||
| to.x = (x * t.a) + (y * t.c) | ||
| to.y = (x * t.b) + (y * t.d) | ||
| if (!isMovePoint) { | ||
| to.x += t.e | ||
| to.y += t.f | ||
| } | ||
| }, | ||
| toLocalPoint(t: IMatrixData, world: IPointData, to?: IPointData, fromOrigin?: boolean): void { | ||
| const { x, y } = world | ||
| toInnerPoint(t: IMatrixData, outer: IPointData, to?: IPointData, isMovePoint?: boolean): void { | ||
| const { x, y } = outer | ||
| const { a, b, c, d } = t | ||
| const s = 1 / (a * d - b * c) | ||
| // local | ||
| to || (to = world) | ||
| // inner | ||
| to || (to = outer) | ||
| to.x = (x * d - y * c) * s | ||
| to.y = (y * a - x * b) * s | ||
| if (!fromOrigin) { | ||
| if (!isMovePoint) { | ||
| const { e, f } = t | ||
@@ -124,9 +190,37 @@ to.x -= (e * d - f * c) * s | ||
| empty(matrix: IMatrix): void { | ||
| matrix.a = 1 | ||
| matrix.b = 0 | ||
| matrix.c = 0 | ||
| matrix.d = 1 | ||
| matrix.e = 0 | ||
| matrix.f = 0 | ||
| decompose(t: IMatrixData): IMatrixDecompositionData { | ||
| const { a, b, c, d } = t | ||
| let scaleX = a, scaleY = d, rotation = 0, skewX = 0, skewY = 0 | ||
| if (b || c) { | ||
| const s = a * d - b * c | ||
| const k = a * c + b * d | ||
| if (b) { | ||
| const ab = a * a + b * b | ||
| scaleX = sqrt(ab) | ||
| scaleY = s / scaleX | ||
| const r = a / scaleX | ||
| rotation = b > 0 ? acos(r) : -acos(r) | ||
| skewX = atan(k / ab) / OneRadian | ||
| } else { | ||
| const cd = c * c + d * d | ||
| scaleY = sqrt(cd) | ||
| scaleX = s / scaleY | ||
| const r = c / scaleY | ||
| rotation = PI / 2 - (d > 0 ? acos(-r) : -acos(r)) | ||
| skewY = atan(k / cd) / OneRadian | ||
| } | ||
| rotation /= OneRadian | ||
| } | ||
| return { x: t.e, y: t.f, scaleX, scaleY, rotation, skewX, skewY } | ||
| }, | ||
| reset(t: IMatrix): void { | ||
| M.set(t) | ||
| } | ||
@@ -133,0 +227,0 @@ } |
+8
-4
@@ -32,9 +32,9 @@ import { IPoint, IPointData, IMatrixData } from '@leafer/interface' | ||
| public toLocal(matrix: IMatrixData, to?: IPointData): IPoint { | ||
| P.toLocal(this, matrix, to) | ||
| public toInnerOf(matrix: IMatrixData, to?: IPointData): IPoint { | ||
| P.toInnerOf(this, matrix, to) | ||
| return this | ||
| } | ||
| public toWorld(matrix: IMatrixData, to?: IPointData): IPoint { | ||
| P.toWorld(this, matrix, to) | ||
| public toOuterOf(matrix: IMatrixData, to?: IPointData): IPoint { | ||
| P.toOuterOf(this, matrix, to) | ||
| return this | ||
@@ -59,2 +59,6 @@ } | ||
| public reset(): void { | ||
| P.reset(this) | ||
| } | ||
| } |
+21
-17
@@ -6,3 +6,3 @@ import { IPointData, IMatrixData, IRadiusPointData } from '@leafer/interface' | ||
| const { toLocalPoint, toWorldPoint } = M | ||
| const { toInnerPoint, toOuterPoint } = M | ||
| const { sin, cos, abs, sqrt, atan2 } = Math | ||
@@ -29,29 +29,30 @@ | ||
| rotate(point: IPointData, rotation: number, center?: IPointData): void { | ||
| rotate(t: IPointData, rotation: number, center?: IPointData): void { | ||
| if (!center) center = P.defaultPoint | ||
| const cosR = cos(rotation * OneRadian) | ||
| const sinR = sin(rotation * OneRadian) | ||
| const rx = point.x - center.x | ||
| const ry = point.y - center.y | ||
| point.x = center.x + rx * cosR - ry * sinR | ||
| point.y = center.y + rx * sinR - ry * cosR | ||
| const rx = t.x - center.x | ||
| const ry = t.y - center.y | ||
| t.x = center.x + rx * cosR - ry * sinR | ||
| t.y = center.y + rx * sinR - ry * cosR | ||
| }, | ||
| tempToLocal(t: IPointData, matrix: IMatrixData): IPointData { | ||
| tempToInnerOf(t: IPointData, matrix: IMatrixData): IPointData { | ||
| const { tempPoint: temp } = P | ||
| P.copy(temp, t) | ||
| toLocalPoint(matrix, temp, temp) | ||
| toInnerPoint(matrix, temp, temp) | ||
| return temp | ||
| }, | ||
| tempToLocalRadiusPoint(t: IRadiusPointData, matrix: IMatrixData): IRadiusPointData { | ||
| tempToInnerRadiusPointOf(t: IRadiusPointData, matrix: IMatrixData): IRadiusPointData { | ||
| const { tempRadiusPoint: temp } = P | ||
| P.copy(temp, t) | ||
| P.toLocalRadiusPoint(t, matrix, temp) | ||
| P.toInnerRadiusPointOf(t, matrix, temp) | ||
| return temp | ||
| }, | ||
| toLocalRadiusPoint(t: IRadiusPointData, matrix: IMatrixData, to?: IRadiusPointData): void { | ||
| toInnerRadiusPointOf(t: IRadiusPointData, matrix: IMatrixData, to?: IRadiusPointData): void { | ||
| to || (to = t) | ||
| toLocalPoint(matrix, t, to) | ||
| toInnerPoint(matrix, t, to) | ||
| to.radiusX = t.radiusX / matrix.a | ||
@@ -62,8 +63,8 @@ to.radiusY = t.radiusY / matrix.d | ||
| toLocal(t: IPointData, matrix: IMatrixData, to?: IPointData): void { | ||
| toLocalPoint(matrix, t, to) | ||
| toInnerOf(t: IPointData, matrix: IMatrixData, to?: IPointData): void { | ||
| toInnerPoint(matrix, t, to) | ||
| }, | ||
| toWorld(t: IPointData, matrix: IMatrixData, to?: IPointData): void { | ||
| toWorldPoint(matrix, t, to) | ||
| toOuterOf(t: IPointData, matrix: IMatrixData, to?: IPointData): void { | ||
| toOuterPoint(matrix, t, to) | ||
| }, | ||
@@ -94,6 +95,9 @@ | ||
| return { x: t.x + cos(r) * distance, y: t.y + sin(r) * distance } | ||
| }, | ||
| reset(t: IPointData): void { | ||
| P.reset(t) | ||
| } | ||
| } | ||
| const P = PointHelper |
30329
13.42%788
14.53%