@teachinglab/omd 0.6.1 → 0.6.3
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 +257 -251
- package/README.old.md +137 -137
- package/canvas/core/canvasConfig.js +202 -202
- package/canvas/drawing/segment.js +167 -167
- package/canvas/drawing/stroke.js +385 -385
- package/canvas/events/eventManager.js +444 -444
- package/canvas/events/pointerEventHandler.js +262 -262
- package/canvas/index.js +48 -48
- package/canvas/tools/PointerTool.js +71 -71
- package/canvas/tools/tool.js +222 -222
- package/canvas/utils/boundingBox.js +377 -377
- package/canvas/utils/mathUtils.js +258 -258
- package/docs/api/configuration-options.md +198 -198
- package/docs/api/eventManager.md +82 -82
- package/docs/api/focusFrameManager.md +144 -144
- package/docs/api/index.md +105 -105
- package/docs/api/main.md +62 -62
- package/docs/api/omdBinaryExpressionNode.md +86 -86
- package/docs/api/omdCanvas.md +83 -83
- package/docs/api/omdConfigManager.md +112 -112
- package/docs/api/omdConstantNode.md +52 -52
- package/docs/api/omdDisplay.md +87 -87
- package/docs/api/omdEquationNode.md +174 -174
- package/docs/api/omdEquationSequenceNode.md +258 -258
- package/docs/api/omdEquationStack.md +192 -192
- package/docs/api/omdFunctionNode.md +82 -82
- package/docs/api/omdGroupNode.md +78 -78
- package/docs/api/omdHelpers.md +87 -87
- package/docs/api/omdLeafNode.md +85 -85
- package/docs/api/omdNode.md +201 -201
- package/docs/api/omdOperationDisplayNode.md +117 -117
- package/docs/api/omdOperatorNode.md +91 -91
- package/docs/api/omdParenthesisNode.md +133 -133
- package/docs/api/omdPopup.md +191 -191
- package/docs/api/omdPowerNode.md +131 -131
- package/docs/api/omdRationalNode.md +144 -144
- package/docs/api/omdSequenceNode.md +128 -128
- package/docs/api/omdSimplification.md +78 -78
- package/docs/api/omdSqrtNode.md +144 -144
- package/docs/api/omdStepVisualizer.md +146 -146
- package/docs/api/omdStepVisualizerHighlighting.md +65 -65
- package/docs/api/omdStepVisualizerInteractiveSteps.md +108 -108
- package/docs/api/omdStepVisualizerLayout.md +70 -70
- package/docs/api/omdStepVisualizerNodeUtils.md +140 -140
- package/docs/api/omdStepVisualizerTextBoxes.md +76 -76
- package/docs/api/omdToolbar.md +130 -130
- package/docs/api/omdTranscriptionService.md +95 -95
- package/docs/api/omdTreeDiff.md +169 -169
- package/docs/api/omdUnaryExpressionNode.md +137 -137
- package/docs/api/omdUtilities.md +82 -82
- package/docs/api/omdVariableNode.md +123 -123
- package/docs/api/selectTool.md +74 -74
- package/docs/api/simplificationEngine.md +97 -97
- package/docs/api/simplificationRules.md +76 -76
- package/docs/api/simplificationUtils.md +64 -64
- package/docs/api/transcribe.md +43 -43
- package/docs/api-reference.md +85 -85
- package/docs/index.html +453 -453
- package/docs/index.md +38 -38
- package/docs/omd-objects.md +258 -258
- package/index.js +79 -79
- package/jsvg/index.js +3 -0
- package/jsvg/jsvg.js +898 -898
- package/jsvg/jsvgComponents.js +357 -358
- package/npm-docs/DOCUMENTATION_SUMMARY.md +220 -220
- package/npm-docs/README.md +251 -251
- package/npm-docs/api/api-reference.md +85 -85
- package/npm-docs/api/configuration-options.md +198 -198
- package/npm-docs/api/eventManager.md +82 -82
- package/npm-docs/api/expression-nodes.md +561 -561
- package/npm-docs/api/focusFrameManager.md +144 -144
- package/npm-docs/api/index.md +105 -105
- package/npm-docs/api/main.md +62 -62
- package/npm-docs/api/omdBinaryExpressionNode.md +86 -86
- package/npm-docs/api/omdCanvas.md +83 -83
- package/npm-docs/api/omdConfigManager.md +112 -112
- package/npm-docs/api/omdConstantNode.md +52 -52
- package/npm-docs/api/omdDisplay.md +87 -87
- package/npm-docs/api/omdEquationNode.md +174 -174
- package/npm-docs/api/omdEquationSequenceNode.md +258 -258
- package/npm-docs/api/omdEquationStack.md +192 -192
- package/npm-docs/api/omdFunctionNode.md +82 -82
- package/npm-docs/api/omdGroupNode.md +78 -78
- package/npm-docs/api/omdHelpers.md +87 -87
- package/npm-docs/api/omdLeafNode.md +85 -85
- package/npm-docs/api/omdNode.md +201 -201
- package/npm-docs/api/omdOperationDisplayNode.md +117 -117
- package/npm-docs/api/omdOperatorNode.md +91 -91
- package/npm-docs/api/omdParenthesisNode.md +133 -133
- package/npm-docs/api/omdPopup.md +191 -191
- package/npm-docs/api/omdPowerNode.md +131 -131
- package/npm-docs/api/omdRationalNode.md +144 -144
- package/npm-docs/api/omdSequenceNode.md +128 -128
- package/npm-docs/api/omdSimplification.md +78 -78
- package/npm-docs/api/omdSqrtNode.md +144 -144
- package/npm-docs/api/omdStepVisualizer.md +146 -146
- package/npm-docs/api/omdStepVisualizerHighlighting.md +65 -65
- package/npm-docs/api/omdStepVisualizerInteractiveSteps.md +108 -108
- package/npm-docs/api/omdStepVisualizerLayout.md +70 -70
- package/npm-docs/api/omdStepVisualizerNodeUtils.md +140 -140
- package/npm-docs/api/omdStepVisualizerTextBoxes.md +76 -76
- package/npm-docs/api/omdToolbar.md +130 -130
- package/npm-docs/api/omdTranscriptionService.md +95 -95
- package/npm-docs/api/omdTreeDiff.md +169 -169
- package/npm-docs/api/omdUnaryExpressionNode.md +137 -137
- package/npm-docs/api/omdUtilities.md +82 -82
- package/npm-docs/api/omdVariableNode.md +123 -123
- package/npm-docs/api/selectTool.md +74 -74
- package/npm-docs/api/simplificationEngine.md +97 -97
- package/npm-docs/api/simplificationRules.md +76 -76
- package/npm-docs/api/simplificationUtils.md +64 -64
- package/npm-docs/api/transcribe.md +43 -43
- package/npm-docs/guides/equations.md +854 -854
- package/npm-docs/guides/factory-functions.md +354 -354
- package/npm-docs/guides/getting-started.md +318 -318
- package/npm-docs/guides/quick-examples.md +525 -525
- package/npm-docs/guides/visualizations.md +682 -682
- package/npm-docs/index.html +12 -0
- package/npm-docs/json-schemas.md +826 -826
- package/omd/config/omdConfigManager.js +279 -267
- package/omd/core/index.js +158 -158
- package/omd/core/omdEquationStack.js +606 -547
- package/omd/core/omdUtilities.js +113 -113
- package/omd/display/omdDisplay.js +1045 -963
- package/omd/display/omdToolbar.js +501 -501
- package/omd/nodes/omdBinaryExpressionNode.js +459 -459
- package/omd/nodes/omdConstantNode.js +141 -141
- package/omd/nodes/omdEquationNode.js +1327 -1327
- package/omd/nodes/omdFunctionNode.js +351 -351
- package/omd/nodes/omdGroupNode.js +67 -67
- package/omd/nodes/omdLeafNode.js +76 -76
- package/omd/nodes/omdNode.js +556 -556
- package/omd/nodes/omdOperationDisplayNode.js +321 -321
- package/omd/nodes/omdOperatorNode.js +108 -108
- package/omd/nodes/omdParenthesisNode.js +292 -292
- package/omd/nodes/omdPowerNode.js +235 -235
- package/omd/nodes/omdRationalNode.js +295 -295
- package/omd/nodes/omdSqrtNode.js +307 -307
- package/omd/nodes/omdUnaryExpressionNode.js +227 -227
- package/omd/nodes/omdVariableNode.js +122 -122
- package/omd/simplification/omdSimplification.js +140 -140
- package/omd/simplification/omdSimplificationEngine.js +887 -887
- package/omd/simplification/package.json +5 -5
- package/omd/simplification/rules/binaryRules.js +1037 -1037
- package/omd/simplification/rules/functionRules.js +111 -111
- package/omd/simplification/rules/index.js +48 -48
- package/omd/simplification/rules/parenthesisRules.js +19 -19
- package/omd/simplification/rules/powerRules.js +143 -143
- package/omd/simplification/rules/rationalRules.js +725 -725
- package/omd/simplification/rules/sqrtRules.js +48 -48
- package/omd/simplification/rules/unaryRules.js +37 -37
- package/omd/simplification/simplificationRules.js +31 -31
- package/omd/simplification/simplificationUtils.js +1055 -1055
- package/omd/step-visualizer/omdStepVisualizer.js +947 -947
- package/omd/step-visualizer/omdStepVisualizerHighlighting.js +246 -246
- package/omd/step-visualizer/omdStepVisualizerLayout.js +892 -892
- package/omd/step-visualizer/omdStepVisualizerTextBoxes.js +200 -200
- package/omd/utils/aiNextEquationStep.js +106 -106
- package/omd/utils/omdNodeOverlay.js +638 -638
- package/omd/utils/omdPopup.js +1203 -1203
- package/omd/utils/omdStepVisualizerInteractiveSteps.js +684 -684
- package/omd/utils/omdStepVisualizerNodeUtils.js +267 -267
- package/omd/utils/omdTranscriptionService.js +123 -123
- package/omd/utils/omdTreeDiff.js +733 -733
- package/package.json +59 -57
- package/readme.html +184 -120
- package/src/index.js +74 -74
- package/src/json-schemas.md +576 -576
- package/src/omd-json-samples.js +147 -147
- package/src/omdApp.js +391 -391
- package/src/omdAppCanvas.js +335 -335
- package/src/omdBalanceHanger.js +199 -199
- package/src/omdColor.js +13 -13
- package/src/omdCoordinatePlane.js +541 -541
- package/src/omdExpression.js +115 -115
- package/src/omdFactory.js +150 -150
- package/src/omdFunction.js +114 -114
- package/src/omdMetaExpression.js +290 -290
- package/src/omdNaturalExpression.js +563 -563
- package/src/omdNode.js +383 -383
- package/src/omdNumber.js +52 -52
- package/src/omdNumberLine.js +114 -112
- package/src/omdNumberTile.js +118 -118
- package/src/omdOperator.js +72 -72
- package/src/omdPowerExpression.js +91 -91
- package/src/omdProblem.js +259 -259
- package/src/omdRatioChart.js +251 -251
- package/src/omdRationalExpression.js +114 -114
- package/src/omdSampleData.js +215 -215
- package/src/omdShapes.js +512 -512
- package/src/omdSpinner.js +151 -151
- package/src/omdString.js +49 -49
- package/src/omdTable.js +498 -498
- package/src/omdTapeDiagram.js +244 -244
- package/src/omdTerm.js +91 -91
- package/src/omdTileEquation.js +349 -349
- package/src/omdUtils.js +84 -84
- package/src/omdVariable.js +51 -51
|
@@ -1,259 +1,259 @@
|
|
|
1
|
-
export class mathUtils {
|
|
2
|
-
/**
|
|
3
|
-
* Calculate distance between two points
|
|
4
|
-
* @param {Object} p1 - First point {x, y}
|
|
5
|
-
* @param {Object} p2 - Second point {x, y}
|
|
6
|
-
* @returns {number} Distance
|
|
7
|
-
*/
|
|
8
|
-
static distance(p1, p2) {
|
|
9
|
-
const dx = p2.x - p1.x;
|
|
10
|
-
const dy = p2.y - p1.y;
|
|
11
|
-
return Math.sqrt(dx * dx + dy * dy);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Calculate squared distance (faster than distance when just comparing)
|
|
16
|
-
* @param {Object} p1 - First point {x, y}
|
|
17
|
-
* @param {Object} p2 - Second point {x, y}
|
|
18
|
-
* @returns {number} Squared distance
|
|
19
|
-
*/
|
|
20
|
-
static distanceSquared(p1, p2) {
|
|
21
|
-
const dx = p2.x - p1.x;
|
|
22
|
-
const dy = p2.y - p1.y;
|
|
23
|
-
return dx * dx + dy * dy;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Calculate angle between two points
|
|
28
|
-
* @param {Object} p1 - First point {x, y}
|
|
29
|
-
* @param {Object} p2 - Second point {x, y}
|
|
30
|
-
* @returns {number} Angle in radians
|
|
31
|
-
*/
|
|
32
|
-
static angle(p1, p2) {
|
|
33
|
-
return Math.atan2(p2.y - p1.y, p2.x - p1.x);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Calculate angle in degrees
|
|
38
|
-
* @param {Object} p1 - First point {x, y}
|
|
39
|
-
* @param {Object} p2 - Second point {x, y}
|
|
40
|
-
* @returns {number} Angle in degrees
|
|
41
|
-
*/
|
|
42
|
-
static angleDegrees(p1, p2) {
|
|
43
|
-
return this.angle(p1, p2) * 180 / Math.PI;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Linear interpolation between two values
|
|
48
|
-
* @param {number} a - Start value
|
|
49
|
-
* @param {number} b - End value
|
|
50
|
-
* @param {number} t - Interpolation factor (0-1)
|
|
51
|
-
* @returns {number} Interpolated value
|
|
52
|
-
*/
|
|
53
|
-
static lerp(a, b, t) {
|
|
54
|
-
return a + (b - a) * t;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Linear interpolation between two points
|
|
59
|
-
* @param {Object} p1 - Start point {x, y}
|
|
60
|
-
* @param {Object} p2 - End point {x, y}
|
|
61
|
-
* @param {number} t - Interpolation factor (0-1)
|
|
62
|
-
* @returns {Object} Interpolated point {x, y}
|
|
63
|
-
*/
|
|
64
|
-
static lerpPoint(p1, p2, t) {
|
|
65
|
-
return {
|
|
66
|
-
x: this.lerp(p1.x, p2.x, t),
|
|
67
|
-
y: this.lerp(p1.y, p2.y, t)
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Clamp value between min and max
|
|
73
|
-
* @param {number} value - Value to clamp
|
|
74
|
-
* @param {number} min - Minimum value
|
|
75
|
-
* @param {number} max - Maximum value
|
|
76
|
-
* @returns {number} Clamped value
|
|
77
|
-
*/
|
|
78
|
-
static clamp(value, min, max) {
|
|
79
|
-
return Math.min(Math.max(value, min), max);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Normalize value from one range to another
|
|
84
|
-
* @param {number} value - Input value
|
|
85
|
-
* @param {number} inMin - Input range minimum
|
|
86
|
-
* @param {number} inMax - Input range maximum
|
|
87
|
-
* @param {number} outMin - Output range minimum
|
|
88
|
-
* @param {number} outMax - Output range maximum
|
|
89
|
-
* @returns {number} Normalized value
|
|
90
|
-
*/
|
|
91
|
-
static map(value, inMin, inMax, outMin, outMax) {
|
|
92
|
-
return (value - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Calculate distance from point to line segment
|
|
97
|
-
* @param {Object} point - Point {x, y}
|
|
98
|
-
* @param {Object} lineStart - Line start {x, y}
|
|
99
|
-
* @param {Object} lineEnd - Line end {x, y}
|
|
100
|
-
* @returns {number} Distance
|
|
101
|
-
*/
|
|
102
|
-
static distanceToLineSegment(point, lineStart, lineEnd) {
|
|
103
|
-
const dx = lineEnd.x - lineStart.x;
|
|
104
|
-
const dy = lineEnd.y - lineStart.y;
|
|
105
|
-
const length = Math.sqrt(dx * dx + dy * dy);
|
|
106
|
-
|
|
107
|
-
if (length === 0) {
|
|
108
|
-
return this.distance(point, lineStart);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const t = Math.max(0, Math.min(1, ((point.x - lineStart.x) * dx + (point.y - lineStart.y) * dy) / (length * length)));
|
|
112
|
-
const projection = {
|
|
113
|
-
x: lineStart.x + t * dx,
|
|
114
|
-
y: lineStart.y + t * dy
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
return this.distance(point, projection);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
/**
|
|
121
|
-
* Check if point is inside circle
|
|
122
|
-
* @param {Object} point - Point {x, y}
|
|
123
|
-
* @param {Object} center - Circle center {x, y}
|
|
124
|
-
* @param {number} radius - Circle radius
|
|
125
|
-
* @returns {boolean} True if point is inside circle
|
|
126
|
-
*/
|
|
127
|
-
static pointInCircle(point, center, radius) {
|
|
128
|
-
return this.distanceSquared(point, center) <= radius * radius;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Check if point is inside rectangle
|
|
133
|
-
* @param {Object} point - Point {x, y}
|
|
134
|
-
* @param {Object} rect - Rectangle {x, y, width, height}
|
|
135
|
-
* @returns {boolean} True if point is inside rectangle
|
|
136
|
-
*/
|
|
137
|
-
static pointInRect(point, rect) {
|
|
138
|
-
return point.x >= rect.x &&
|
|
139
|
-
point.x <= rect.x + rect.width &&
|
|
140
|
-
point.y >= rect.y &&
|
|
141
|
-
point.y <= rect.y + rect.height;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Smooth an array of points using averaging
|
|
146
|
-
* @param {Array} points - Array of points
|
|
147
|
-
* @param {number} factor - Smoothing factor (0-1)
|
|
148
|
-
* @returns {Array} Smoothed points
|
|
149
|
-
*/
|
|
150
|
-
static smoothPoints(points, factor = 0.5) {
|
|
151
|
-
if (points.length < 3) return points;
|
|
152
|
-
|
|
153
|
-
const smoothed = [points[0]]; // Keep first point
|
|
154
|
-
|
|
155
|
-
for (let i = 1; i < points.length - 1; i++) {
|
|
156
|
-
const prev = points[i - 1];
|
|
157
|
-
const curr = points[i];
|
|
158
|
-
const next = points[i + 1];
|
|
159
|
-
|
|
160
|
-
const avgX = (prev.x + curr.x + next.x) / 3;
|
|
161
|
-
const avgY = (prev.y + curr.y + next.y) / 3;
|
|
162
|
-
|
|
163
|
-
smoothed.push({
|
|
164
|
-
x: this.lerp(curr.x, avgX, factor),
|
|
165
|
-
y: this.lerp(curr.y, avgY, factor),
|
|
166
|
-
...curr // Preserve other properties
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
smoothed.push(points[points.length - 1]); // Keep last point
|
|
171
|
-
return smoothed;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Generate bezier curve points
|
|
176
|
-
* @param {Object} p0 - Control point 0
|
|
177
|
-
* @param {Object} p1 - Control point 1
|
|
178
|
-
* @param {Object} p2 - Control point 2
|
|
179
|
-
* @param {Object} p3 - Control point 3
|
|
180
|
-
* @param {number} steps - Number of steps
|
|
181
|
-
* @returns {Array} Curve points
|
|
182
|
-
*/
|
|
183
|
-
static bezierCurve(p0, p1, p2, p3, steps = 20) {
|
|
184
|
-
const points = [];
|
|
185
|
-
|
|
186
|
-
for (let i = 0; i <= steps; i++) {
|
|
187
|
-
const t = i / steps;
|
|
188
|
-
const u = 1 - t;
|
|
189
|
-
const tt = t * t;
|
|
190
|
-
const uu = u * u;
|
|
191
|
-
const uuu = uu * u;
|
|
192
|
-
const ttt = tt * t;
|
|
193
|
-
|
|
194
|
-
const x = uuu * p0.x + 3 * uu * t * p1.x + 3 * u * tt * p2.x + ttt * p3.x;
|
|
195
|
-
const y = uuu * p0.y + 3 * uu * t * p1.y + 3 * u * tt * p2.y + ttt * p3.y;
|
|
196
|
-
|
|
197
|
-
points.push({ x, y });
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
return points;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* Convert degrees to radians
|
|
205
|
-
* @param {number} degrees - Angle in degrees
|
|
206
|
-
* @returns {number} Angle in radians
|
|
207
|
-
*/
|
|
208
|
-
static degreesToRadians(degrees) {
|
|
209
|
-
return degrees * Math.PI / 180;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Convert radians to degrees
|
|
214
|
-
* @param {number} radians - Angle in radians
|
|
215
|
-
* @returns {number} Angle in degrees
|
|
216
|
-
*/
|
|
217
|
-
static radiansToDegrees(radians) {
|
|
218
|
-
return radians * 180 / Math.PI;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Rotate point around center
|
|
223
|
-
* @param {Object} point - Point to rotate {x, y}
|
|
224
|
-
* @param {Object} center - Center of rotation {x, y}
|
|
225
|
-
* @param {number} angle - Rotation angle in radians
|
|
226
|
-
* @returns {Object} Rotated point {x, y}
|
|
227
|
-
*/
|
|
228
|
-
static rotatePoint(point, center, angle) {
|
|
229
|
-
const cos = Math.cos(angle);
|
|
230
|
-
const sin = Math.sin(angle);
|
|
231
|
-
const dx = point.x - center.x;
|
|
232
|
-
const dy = point.y - center.y;
|
|
233
|
-
|
|
234
|
-
return {
|
|
235
|
-
x: center.x + dx * cos - dy * sin,
|
|
236
|
-
y: center.y + dx * sin + dy * cos
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Generate random number between min and max
|
|
242
|
-
* @param {number} min - Minimum value
|
|
243
|
-
* @param {number} max - Maximum value
|
|
244
|
-
* @returns {number} Random number
|
|
245
|
-
*/
|
|
246
|
-
static random(min, max) {
|
|
247
|
-
return Math.random() * (max - min) + min;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
/**
|
|
251
|
-
* Generate random integer between min and max
|
|
252
|
-
* @param {number} min - Minimum value (inclusive)
|
|
253
|
-
* @param {number} max - Maximum value (inclusive)
|
|
254
|
-
* @returns {number} Random integer
|
|
255
|
-
*/
|
|
256
|
-
static randomInt(min, max) {
|
|
257
|
-
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
258
|
-
}
|
|
1
|
+
export class mathUtils {
|
|
2
|
+
/**
|
|
3
|
+
* Calculate distance between two points
|
|
4
|
+
* @param {Object} p1 - First point {x, y}
|
|
5
|
+
* @param {Object} p2 - Second point {x, y}
|
|
6
|
+
* @returns {number} Distance
|
|
7
|
+
*/
|
|
8
|
+
static distance(p1, p2) {
|
|
9
|
+
const dx = p2.x - p1.x;
|
|
10
|
+
const dy = p2.y - p1.y;
|
|
11
|
+
return Math.sqrt(dx * dx + dy * dy);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Calculate squared distance (faster than distance when just comparing)
|
|
16
|
+
* @param {Object} p1 - First point {x, y}
|
|
17
|
+
* @param {Object} p2 - Second point {x, y}
|
|
18
|
+
* @returns {number} Squared distance
|
|
19
|
+
*/
|
|
20
|
+
static distanceSquared(p1, p2) {
|
|
21
|
+
const dx = p2.x - p1.x;
|
|
22
|
+
const dy = p2.y - p1.y;
|
|
23
|
+
return dx * dx + dy * dy;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Calculate angle between two points
|
|
28
|
+
* @param {Object} p1 - First point {x, y}
|
|
29
|
+
* @param {Object} p2 - Second point {x, y}
|
|
30
|
+
* @returns {number} Angle in radians
|
|
31
|
+
*/
|
|
32
|
+
static angle(p1, p2) {
|
|
33
|
+
return Math.atan2(p2.y - p1.y, p2.x - p1.x);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Calculate angle in degrees
|
|
38
|
+
* @param {Object} p1 - First point {x, y}
|
|
39
|
+
* @param {Object} p2 - Second point {x, y}
|
|
40
|
+
* @returns {number} Angle in degrees
|
|
41
|
+
*/
|
|
42
|
+
static angleDegrees(p1, p2) {
|
|
43
|
+
return this.angle(p1, p2) * 180 / Math.PI;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Linear interpolation between two values
|
|
48
|
+
* @param {number} a - Start value
|
|
49
|
+
* @param {number} b - End value
|
|
50
|
+
* @param {number} t - Interpolation factor (0-1)
|
|
51
|
+
* @returns {number} Interpolated value
|
|
52
|
+
*/
|
|
53
|
+
static lerp(a, b, t) {
|
|
54
|
+
return a + (b - a) * t;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Linear interpolation between two points
|
|
59
|
+
* @param {Object} p1 - Start point {x, y}
|
|
60
|
+
* @param {Object} p2 - End point {x, y}
|
|
61
|
+
* @param {number} t - Interpolation factor (0-1)
|
|
62
|
+
* @returns {Object} Interpolated point {x, y}
|
|
63
|
+
*/
|
|
64
|
+
static lerpPoint(p1, p2, t) {
|
|
65
|
+
return {
|
|
66
|
+
x: this.lerp(p1.x, p2.x, t),
|
|
67
|
+
y: this.lerp(p1.y, p2.y, t)
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Clamp value between min and max
|
|
73
|
+
* @param {number} value - Value to clamp
|
|
74
|
+
* @param {number} min - Minimum value
|
|
75
|
+
* @param {number} max - Maximum value
|
|
76
|
+
* @returns {number} Clamped value
|
|
77
|
+
*/
|
|
78
|
+
static clamp(value, min, max) {
|
|
79
|
+
return Math.min(Math.max(value, min), max);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Normalize value from one range to another
|
|
84
|
+
* @param {number} value - Input value
|
|
85
|
+
* @param {number} inMin - Input range minimum
|
|
86
|
+
* @param {number} inMax - Input range maximum
|
|
87
|
+
* @param {number} outMin - Output range minimum
|
|
88
|
+
* @param {number} outMax - Output range maximum
|
|
89
|
+
* @returns {number} Normalized value
|
|
90
|
+
*/
|
|
91
|
+
static map(value, inMin, inMax, outMin, outMax) {
|
|
92
|
+
return (value - inMin) * (outMax - outMin) / (inMax - inMin) + outMin;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Calculate distance from point to line segment
|
|
97
|
+
* @param {Object} point - Point {x, y}
|
|
98
|
+
* @param {Object} lineStart - Line start {x, y}
|
|
99
|
+
* @param {Object} lineEnd - Line end {x, y}
|
|
100
|
+
* @returns {number} Distance
|
|
101
|
+
*/
|
|
102
|
+
static distanceToLineSegment(point, lineStart, lineEnd) {
|
|
103
|
+
const dx = lineEnd.x - lineStart.x;
|
|
104
|
+
const dy = lineEnd.y - lineStart.y;
|
|
105
|
+
const length = Math.sqrt(dx * dx + dy * dy);
|
|
106
|
+
|
|
107
|
+
if (length === 0) {
|
|
108
|
+
return this.distance(point, lineStart);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const t = Math.max(0, Math.min(1, ((point.x - lineStart.x) * dx + (point.y - lineStart.y) * dy) / (length * length)));
|
|
112
|
+
const projection = {
|
|
113
|
+
x: lineStart.x + t * dx,
|
|
114
|
+
y: lineStart.y + t * dy
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
return this.distance(point, projection);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Check if point is inside circle
|
|
122
|
+
* @param {Object} point - Point {x, y}
|
|
123
|
+
* @param {Object} center - Circle center {x, y}
|
|
124
|
+
* @param {number} radius - Circle radius
|
|
125
|
+
* @returns {boolean} True if point is inside circle
|
|
126
|
+
*/
|
|
127
|
+
static pointInCircle(point, center, radius) {
|
|
128
|
+
return this.distanceSquared(point, center) <= radius * radius;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Check if point is inside rectangle
|
|
133
|
+
* @param {Object} point - Point {x, y}
|
|
134
|
+
* @param {Object} rect - Rectangle {x, y, width, height}
|
|
135
|
+
* @returns {boolean} True if point is inside rectangle
|
|
136
|
+
*/
|
|
137
|
+
static pointInRect(point, rect) {
|
|
138
|
+
return point.x >= rect.x &&
|
|
139
|
+
point.x <= rect.x + rect.width &&
|
|
140
|
+
point.y >= rect.y &&
|
|
141
|
+
point.y <= rect.y + rect.height;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Smooth an array of points using averaging
|
|
146
|
+
* @param {Array} points - Array of points
|
|
147
|
+
* @param {number} factor - Smoothing factor (0-1)
|
|
148
|
+
* @returns {Array} Smoothed points
|
|
149
|
+
*/
|
|
150
|
+
static smoothPoints(points, factor = 0.5) {
|
|
151
|
+
if (points.length < 3) return points;
|
|
152
|
+
|
|
153
|
+
const smoothed = [points[0]]; // Keep first point
|
|
154
|
+
|
|
155
|
+
for (let i = 1; i < points.length - 1; i++) {
|
|
156
|
+
const prev = points[i - 1];
|
|
157
|
+
const curr = points[i];
|
|
158
|
+
const next = points[i + 1];
|
|
159
|
+
|
|
160
|
+
const avgX = (prev.x + curr.x + next.x) / 3;
|
|
161
|
+
const avgY = (prev.y + curr.y + next.y) / 3;
|
|
162
|
+
|
|
163
|
+
smoothed.push({
|
|
164
|
+
x: this.lerp(curr.x, avgX, factor),
|
|
165
|
+
y: this.lerp(curr.y, avgY, factor),
|
|
166
|
+
...curr // Preserve other properties
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
smoothed.push(points[points.length - 1]); // Keep last point
|
|
171
|
+
return smoothed;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Generate bezier curve points
|
|
176
|
+
* @param {Object} p0 - Control point 0
|
|
177
|
+
* @param {Object} p1 - Control point 1
|
|
178
|
+
* @param {Object} p2 - Control point 2
|
|
179
|
+
* @param {Object} p3 - Control point 3
|
|
180
|
+
* @param {number} steps - Number of steps
|
|
181
|
+
* @returns {Array} Curve points
|
|
182
|
+
*/
|
|
183
|
+
static bezierCurve(p0, p1, p2, p3, steps = 20) {
|
|
184
|
+
const points = [];
|
|
185
|
+
|
|
186
|
+
for (let i = 0; i <= steps; i++) {
|
|
187
|
+
const t = i / steps;
|
|
188
|
+
const u = 1 - t;
|
|
189
|
+
const tt = t * t;
|
|
190
|
+
const uu = u * u;
|
|
191
|
+
const uuu = uu * u;
|
|
192
|
+
const ttt = tt * t;
|
|
193
|
+
|
|
194
|
+
const x = uuu * p0.x + 3 * uu * t * p1.x + 3 * u * tt * p2.x + ttt * p3.x;
|
|
195
|
+
const y = uuu * p0.y + 3 * uu * t * p1.y + 3 * u * tt * p2.y + ttt * p3.y;
|
|
196
|
+
|
|
197
|
+
points.push({ x, y });
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return points;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Convert degrees to radians
|
|
205
|
+
* @param {number} degrees - Angle in degrees
|
|
206
|
+
* @returns {number} Angle in radians
|
|
207
|
+
*/
|
|
208
|
+
static degreesToRadians(degrees) {
|
|
209
|
+
return degrees * Math.PI / 180;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Convert radians to degrees
|
|
214
|
+
* @param {number} radians - Angle in radians
|
|
215
|
+
* @returns {number} Angle in degrees
|
|
216
|
+
*/
|
|
217
|
+
static radiansToDegrees(radians) {
|
|
218
|
+
return radians * 180 / Math.PI;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Rotate point around center
|
|
223
|
+
* @param {Object} point - Point to rotate {x, y}
|
|
224
|
+
* @param {Object} center - Center of rotation {x, y}
|
|
225
|
+
* @param {number} angle - Rotation angle in radians
|
|
226
|
+
* @returns {Object} Rotated point {x, y}
|
|
227
|
+
*/
|
|
228
|
+
static rotatePoint(point, center, angle) {
|
|
229
|
+
const cos = Math.cos(angle);
|
|
230
|
+
const sin = Math.sin(angle);
|
|
231
|
+
const dx = point.x - center.x;
|
|
232
|
+
const dy = point.y - center.y;
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
x: center.x + dx * cos - dy * sin,
|
|
236
|
+
y: center.y + dx * sin + dy * cos
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Generate random number between min and max
|
|
242
|
+
* @param {number} min - Minimum value
|
|
243
|
+
* @param {number} max - Maximum value
|
|
244
|
+
* @returns {number} Random number
|
|
245
|
+
*/
|
|
246
|
+
static random(min, max) {
|
|
247
|
+
return Math.random() * (max - min) + min;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Generate random integer between min and max
|
|
252
|
+
* @param {number} min - Minimum value (inclusive)
|
|
253
|
+
* @param {number} max - Maximum value (inclusive)
|
|
254
|
+
* @returns {number} Random integer
|
|
255
|
+
*/
|
|
256
|
+
static randomInt(min, max) {
|
|
257
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
258
|
+
}
|
|
259
259
|
}
|