@fbltd/math 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1 @@
1
+ # math
@@ -0,0 +1,6 @@
1
+ {
2
+ "mode": "development",
3
+ "entry": "index.ts",
4
+ "output": "dist/bundled-file.js",
5
+ "library": "math"
6
+ }
package/index.ts ADDED
@@ -0,0 +1 @@
1
+ export * from './src'
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@fbltd/math",
3
+ "version": "1.0.2",
4
+ "description": "",
5
+ "main": "index.ts",
6
+ "scripts": {
7
+ "build": "node_modules/.bin/tsc",
8
+ "test": "echo \"Error: no test specified\" && exit 1"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/GlennMiller1991/math.git"
13
+ },
14
+ "author": "",
15
+ "license": "ISC",
16
+ "bugs": {
17
+ "url": "https://github.com/GlennMiller1991/math/issues"
18
+ },
19
+ "homepage": "https://github.com/GlennMiller1991/math#readme",
20
+ "dependencies": {
21
+ "@fbltd/bundler": "^2.0.15"
22
+ },
23
+ "publishConfig": {
24
+ "access": "public"
25
+ }
26
+ }
package/src/angle.ts ADDED
@@ -0,0 +1,87 @@
1
+ import {isCorrectNumber, toPositive} from "./utils";
2
+
3
+ export enum AngleUnits {
4
+ Deg = 0,
5
+ Rad = 1,
6
+ Turn = 2,
7
+ }
8
+
9
+
10
+ export class Angle {
11
+
12
+ // region Converters
13
+ static toRad(angle: number, unit: AngleUnits = AngleUnits.Deg) {
14
+ switch (unit) {
15
+ case AngleUnits.Rad:
16
+ return angle
17
+ case AngleUnits.Deg:
18
+ return angle * Math.PI / 180
19
+ case AngleUnits.Turn:
20
+ return Math.PI * 2 * angle
21
+ }
22
+ }
23
+
24
+ static toTurn(angle: number, unit: AngleUnits = AngleUnits.Deg) {
25
+ switch (unit) {
26
+ case AngleUnits.Turn:
27
+ return angle
28
+ case AngleUnits.Deg:
29
+ return angle / 360
30
+ case AngleUnits.Rad:
31
+ return angle / (Math.PI * 2)
32
+ }
33
+ }
34
+
35
+ static toDeg(angle: number, unit: AngleUnits = AngleUnits.Rad) {
36
+ switch (unit) {
37
+ case AngleUnits.Deg:
38
+ return angle
39
+ case AngleUnits.Turn:
40
+ return angle * 360
41
+ case AngleUnits.Rad:
42
+ return angle * 180 / Math.PI
43
+ }
44
+ }
45
+
46
+ // endregion Converters
47
+
48
+ static toPositive(angle: number, unit: AngleUnits) {
49
+ switch (unit) {
50
+ case AngleUnits.Deg:
51
+ return toPositive(angle, 360)
52
+ case AngleUnits.Turn:
53
+ return toPositive(angle, 1)
54
+ case AngleUnits.Rad:
55
+ return toPositive(angle, Math.PI * 2)
56
+ }
57
+ }
58
+
59
+ static normalize(angle: number, unit: AngleUnits) {
60
+ switch (unit) {
61
+ // 0 - 359.9999
62
+ case AngleUnits.Deg:
63
+ return Angle.toPositive(angle, unit) % 360
64
+ // 0 - Math.PI * 2
65
+ case AngleUnits.Rad:
66
+ return Angle.toPositive(angle, unit) % (Math.PI * 2)
67
+ // 0 - 1
68
+ case AngleUnits.Turn:
69
+ return Angle.toPositive(angle, unit) % 1
70
+ }
71
+ }
72
+
73
+ // region representation
74
+ static toCSS(angle: number, unit: AngleUnits) {
75
+ if (!isCorrectNumber(angle)) return ''
76
+ return `rotate(${angle}${Angle.angleUnitCorrespondence[unit]})`
77
+ }
78
+
79
+ static angleUnitCorrespondence: Record<AngleUnits, string> = {
80
+ [AngleUnits.Rad]: 'rad',
81
+ [AngleUnits.Turn]: 'turn',
82
+ [AngleUnits.Deg]: 'deg',
83
+ }
84
+ // endregion representation
85
+
86
+ }
87
+
@@ -0,0 +1,11 @@
1
+ export class Color {
2
+ constructor(public red: number, public green: number, public blue: number) {
3
+ this.red = Math.max(Math.min(red, 255), 0)
4
+ this.green = Math.max(Math.min(green, 255), 0)
5
+ this.blue = Math.max(Math.min(blue, 255), 0)
6
+ }
7
+
8
+ toCSS() {
9
+ return `rgb(${this.red}, ${this.green}, ${this.blue})`
10
+ }
11
+ }
@@ -0,0 +1,105 @@
1
+ import {Color} from "./color";
2
+ import {IPoint2} from "../figures";
3
+
4
+ export class ConicGradient {
5
+ colors: { angle: number, color: Color }[]
6
+
7
+ constructor(...colors: { angle: number, color: Color }[]) {
8
+ this.colors = [...colors].sort((a, b) => a.angle - b.angle)
9
+ this.colors.push({
10
+ angle: 1,
11
+ color: this.colors[0].color
12
+ })
13
+ }
14
+
15
+ /**
16
+ * Получить цвет по углу от оси X по часовой стрелке
17
+ * @param angle единица измерения угла должна быть той же самой, что и углы всех передаваемых в констурктор цветов
18
+ */
19
+ getColorAtAngle(angle: number) {
20
+ let prev = undefined
21
+ let next = undefined
22
+ for (let color of this.colors) {
23
+ if (color.angle === angle) return color.color
24
+ if (color.angle < angle) prev = color
25
+ if (color.angle > angle) {
26
+ next = color
27
+ break
28
+ }
29
+ }
30
+
31
+ if (!prev || !next) return undefined
32
+
33
+ const coef = (angle - prev.angle) / (next.angle - prev.angle)
34
+
35
+ return new Color(
36
+ Math.floor((next.color.red - prev.color.red) * coef + prev.color.red),
37
+ Math.floor((next.color.green - prev.color.green) * coef + prev.color.green),
38
+ Math.floor((next.color.blue - prev.color.blue) * coef + prev.color.blue),
39
+ )
40
+ }
41
+
42
+ getAngleByColor(color: Color) {
43
+ let prev: typeof this.colors[number]
44
+ let next = this.colors[0]
45
+ if (color.red === next.color.red && color.green === next.color.green && color.blue === next.color.blue) return next.angle
46
+ for (let i = 1; i < this.colors.length; i++) {
47
+ next = this.colors[i]
48
+ prev = this.colors[i - 1]
49
+ if (color.red === next.color.red && color.green === next.color.green && color.blue === next.color.blue) return next.angle
50
+
51
+ let redDif = next.color.red - prev.color.red
52
+ let greenDif = next.color.green - prev.color.green
53
+ let blueDif = next.color.blue - prev.color.blue
54
+ let redDifColor = color.red - prev.color.red
55
+ let greenDifColor = color.green - prev.color.green
56
+ let blueDifColor = color.blue - prev.color.blue
57
+
58
+ if (
59
+ ((redDifColor >= 0 && redDifColor <= redDif) || (redDifColor <= 0 && redDifColor >= redDif)) &&
60
+ ((greenDifColor >= 0 && greenDifColor <= greenDif) || (greenDifColor <= 0 && greenDifColor >= greenDif)) &&
61
+ ((blueDifColor >= 0 && blueDifColor <= blueDif) || (blueDifColor <= 0 && blueDifColor >= blueDif))
62
+ ) {
63
+
64
+ const redCoef = ((color.red - prev.color.red) / (next.color.red - prev.color.red))
65
+ const greenCoef = ((color.green - prev.color.green) / (next.color.green - prev.color.green))
66
+ const blueCoef = ((color.blue - prev.color.blue) / (next.color.blue - prev.color.blue))
67
+ const coefs = [redCoef, greenCoef, blueCoef].filter(Boolean)
68
+ return (next.angle - prev.angle) * Math.min(...coefs) + prev.angle
69
+ }
70
+ }
71
+ return undefined
72
+ }
73
+
74
+ isColorInRange(color: Color): boolean {
75
+ return Boolean(this.getAngleByColor(color))
76
+ }
77
+
78
+ /**
79
+ * Для использования метода, углы должны быть в Turn единицах измерения
80
+ */
81
+ toCanvas(ctx: CanvasRenderingContext2D, center: IPoint2) {
82
+ const gradient = ctx.createConicGradient(0, ...center as [number, number])
83
+ for (let color of this.colors) {
84
+ gradient.addColorStop(color.angle, color.color.toCSS())
85
+ }
86
+
87
+ return gradient
88
+ }
89
+
90
+ /**
91
+ * Для использования метода, углы должны быть в Turn единицах измерения
92
+ */
93
+ toCSS() {
94
+ let s = ''
95
+
96
+ for (let color of this.colors) {
97
+ if (s) s += ','
98
+ s += `rgb(${color.color.red},${color.color.green},${color.color.blue})`
99
+ }
100
+
101
+ s = `conic-gradient(in srgb from 0.25turn at 50% 50%, ${s})`
102
+ return s
103
+ }
104
+
105
+ }
@@ -0,0 +1,2 @@
1
+ export * from './color'
2
+ export * from './conic.gradient'
@@ -0,0 +1,12 @@
1
+ import {IPoint2} from "./point";
2
+ import {IMatrix2d, Matrix2d} from "../matrix";
3
+
4
+ export class Circle {
5
+ constructor(public center: IPoint2, public r: number) {
6
+
7
+ }
8
+
9
+ transform(matrix: IMatrix2d) {
10
+ this.center = Matrix2d.apply(matrix, this.center)
11
+ }
12
+ }
@@ -0,0 +1,3 @@
1
+ export * from './point'
2
+ export * from './circle'
3
+ export * from './straight-line'
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Точка/вектор
3
+ */
4
+ export type IPoint2 = [number, number]
5
+
6
+ /**
7
+ * Точка/вектор
8
+ */
9
+ export class Point2 {
10
+ static sum(p1: IPoint2, p2: IPoint2): IPoint2 {
11
+ return [
12
+ p1[0] + p2[0],
13
+ p1[1] + p2[1],
14
+ ]
15
+ }
16
+
17
+ static scale(v: IPoint2, factor: number): IPoint2 {
18
+ return [
19
+ v[0] * factor,
20
+ v[1] * factor,
21
+ ]
22
+ }
23
+ }
@@ -0,0 +1,15 @@
1
+ import {IPoint2} from "./point";
2
+ import {IMatrix2d, Matrix2d} from "../matrix";
3
+
4
+ export class StraightLine {
5
+ constructor(public p1: IPoint2, public p2: IPoint2) {
6
+
7
+ }
8
+
9
+ transform(matrix: IMatrix2d, transformThis = false) {
10
+ if (transformThis) {
11
+ return this
12
+ }
13
+ return new StraightLine(Matrix2d.apply(matrix, this.p1), Matrix2d.apply(matrix, this.p2))
14
+ }
15
+ }
package/src/index.ts ADDED
@@ -0,0 +1,6 @@
1
+ export * from './angle'
2
+ export * from './matrix'
3
+ export * from './operator'
4
+ export * from './utils'
5
+ export * from './colors'
6
+ export * from './figures'
package/src/matrix.ts ADDED
@@ -0,0 +1,32 @@
1
+ import {IPoint2} from "./figures";
2
+
3
+ export type IMatrix2d = [
4
+ number, number, number,
5
+ number, number, number,
6
+ ]
7
+
8
+ export const identityMatrix: IMatrix2d = [1, 0, 0, 1, 0, 0]
9
+
10
+ export class Matrix2d {
11
+ static multiply(matrix: IMatrix2d, ...matrices: IMatrix2d[]) {
12
+ for (let m of matrices) {
13
+ matrix = [
14
+ matrix[0] * m[0] + matrix[2] * m[1],
15
+ matrix[1] * m[0] + matrix[3] * m[1],
16
+ matrix[0] * m[2] + matrix[2] * m[3],
17
+ matrix[1] * m[2] + matrix[3] * m[3],
18
+ matrix[0] * m[4] + matrix[2] * m[5] + matrix[4],
19
+ matrix[1] * m[4] + matrix[3] * m[5] + matrix[5],
20
+ ]
21
+ }
22
+
23
+ return matrix
24
+ }
25
+
26
+ static apply(matrix: IMatrix2d, point: IPoint2): IPoint2 {
27
+ return [
28
+ matrix[0] * point[0] + matrix[2] * point[1] + matrix[4],
29
+ matrix[1] * point[0] + matrix[3] * point[1] + matrix[5],
30
+ ]
31
+ }
32
+ }
@@ -0,0 +1,23 @@
1
+ import {IMatrix2d} from "./matrix";
2
+ import {Angle, AngleUnits} from "./angle";
3
+
4
+ export class Operator {
5
+ private static temp1: number
6
+ private static temp2: number
7
+
8
+ /**
9
+ * @param angle поворот в градусах
10
+ */
11
+ static rotateIdentity(angle: number, unit: AngleUnits = AngleUnits.Deg): IMatrix2d {
12
+ angle = Angle.toRad(angle, unit)
13
+ this.temp1 = Math.cos(angle)
14
+ this.temp2 = Math.sin(angle)
15
+ return [
16
+ this.temp1,
17
+ this.temp2,
18
+ -this.temp2,
19
+ this.temp1,
20
+ 0, 0
21
+ ]
22
+ }
23
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,17 @@
1
+ export function approximately(theValue: number, is: number, withPrecision: number = 1e-8) {
2
+ return Math.abs(theValue - is) <= withPrecision
3
+ }
4
+
5
+ export function toPositive(value: number, range: number) {
6
+ if (value >= 0) return Math.abs(value)
7
+ return Math.abs((range + value % range) % range)
8
+ }
9
+
10
+ export function isCorrectNumber(value: any) {
11
+ let v: number = +value
12
+ if (!isNaN(value) && isFinite(value)) {
13
+ v = parseFloat(value)
14
+ return !isNaN(v) && isFinite(v)
15
+ }
16
+ return false
17
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "./node_modules/@fbltd/bundler/tsconfig.json",
3
+ "compilerOptions": {
4
+ "moduleResolution": "Node",
5
+ "outFile": "dist/math.js",
6
+ "module": "AMD",
7
+ "sourceMap": true,
8
+ "declaration": true
9
+ }
10
+ }