@ue-too/math 0.9.4 → 0.10.0
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 -3
- package/index.d.ts +629 -5
- package/index.js +2 -174
- package/index.js.map +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,258 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
<h1 align="center">
|
|
2
|
+
@ue-too/math
|
|
3
|
+
</h1>
|
|
4
|
+
<p align="center">
|
|
5
|
+
Mathematical utilities for 2D and 3D point operations and transformations
|
|
6
|
+
</p>
|
|
3
7
|
|
|
4
|
-
|
|
8
|
+
<div align="center">
|
|
9
|
+
|
|
10
|
+
[](https://www.npmjs.com/package/@ue-too/math)
|
|
11
|
+
[](https://github.com/ue-too/ue-too/blob/main/LICENSE.txt)
|
|
12
|
+
|
|
13
|
+
</div>
|
|
14
|
+
|
|
15
|
+
## Overview
|
|
16
|
+
|
|
17
|
+
`@ue-too/math` provides essential mathematical operations for canvas-based applications, including vector arithmetic, geometric transformations, angle calculations, and point comparisons. It seamlessly handles both 2D and 3D coordinates.
|
|
18
|
+
|
|
19
|
+
### Key Features
|
|
20
|
+
|
|
21
|
+
- **Vector Operations**: Addition, subtraction, scaling, dot product, cross product
|
|
22
|
+
- **Geometric Transformations**: Rotation, axis transformation, coordinate conversion
|
|
23
|
+
- **Angle Utilities**: Normalization, angular difference calculation
|
|
24
|
+
- **Point Utilities**: Distance, interpolation, intersection detection
|
|
25
|
+
- **Comparison Functions**: Approximate equality with configurable precision
|
|
26
|
+
- **2D/3D Support**: All operations work with optional z-coordinates
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install @ue-too/math
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
import { PointCal, Point } from '@ue-too/math';
|
|
38
|
+
|
|
39
|
+
// Vector addition
|
|
40
|
+
const a: Point = { x: 1, y: 2 };
|
|
41
|
+
const b: Point = { x: 3, y: 4 };
|
|
42
|
+
const sum = PointCal.addVector(a, b); // { x: 4, y: 6 }
|
|
43
|
+
|
|
44
|
+
// Calculate magnitude
|
|
45
|
+
const magnitude = PointCal.magnitude(a); // 2.236...
|
|
46
|
+
|
|
47
|
+
// Rotate a point
|
|
48
|
+
const point: Point = { x: 10, y: 0 };
|
|
49
|
+
const rotated = PointCal.rotatePoint(point, Math.PI / 2); // 90 degrees
|
|
50
|
+
// Result: { x: ~0, y: 10 }
|
|
51
|
+
|
|
52
|
+
// Get distance between points
|
|
53
|
+
const distance = PointCal.distanceBetweenPoints(a, b); // 2.828...
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Core APIs
|
|
57
|
+
|
|
58
|
+
### PointCal Class
|
|
59
|
+
|
|
60
|
+
The `PointCal` class provides static methods for all point and vector operations.
|
|
61
|
+
|
|
62
|
+
#### Vector Arithmetic
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
// Add two vectors
|
|
66
|
+
PointCal.addVector(a, b);
|
|
67
|
+
|
|
68
|
+
// Subtract vectors
|
|
69
|
+
PointCal.subVector(a, b);
|
|
70
|
+
|
|
71
|
+
// Scale by scalar
|
|
72
|
+
PointCal.multiplyVectorByScalar(v, 2.5);
|
|
73
|
+
|
|
74
|
+
// Divide by scalar
|
|
75
|
+
PointCal.divideVectorByScalar(v, 2);
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
#### Vector Operations
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
// Magnitude (length) of vector
|
|
82
|
+
PointCal.magnitude(v);
|
|
83
|
+
|
|
84
|
+
// Unit vector (normalized to length 1)
|
|
85
|
+
PointCal.unitVector(v);
|
|
86
|
+
|
|
87
|
+
// Dot product
|
|
88
|
+
PointCal.dotProduct(a, b);
|
|
89
|
+
|
|
90
|
+
// Cross product
|
|
91
|
+
PointCal.crossProduct(a, b);
|
|
92
|
+
|
|
93
|
+
// Unit vector from point a to point b
|
|
94
|
+
PointCal.unitVectorFromA2B(a, b);
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
#### Transformations
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
// Rotate point around origin
|
|
101
|
+
PointCal.rotatePoint(point, angleInRadians);
|
|
102
|
+
|
|
103
|
+
// Rotate point around custom anchor
|
|
104
|
+
PointCal.transformPointWRTAnchor(point, anchor, angleInRadians);
|
|
105
|
+
|
|
106
|
+
// Transform to new axis system
|
|
107
|
+
PointCal.transform2NewAxis(point, angleInRadians);
|
|
108
|
+
|
|
109
|
+
// Flip y-axis (useful for coordinate system conversion)
|
|
110
|
+
PointCal.flipYAxis(point);
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
#### Geometric Calculations
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
// Distance between points
|
|
117
|
+
PointCal.distanceBetweenPoints(a, b);
|
|
118
|
+
|
|
119
|
+
// Linear interpolation (lerp)
|
|
120
|
+
PointCal.linearInterpolation(a, b, 0.5); // Midpoint
|
|
121
|
+
|
|
122
|
+
// Angle from vector a to vector b
|
|
123
|
+
PointCal.angleFromA2B(a, b);
|
|
124
|
+
|
|
125
|
+
// Line segment intersection
|
|
126
|
+
PointCal.getLineIntersection(line1Start, line1End, line2Start, line2End);
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Angle Utilities
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
import { normalizeAngleZero2TwoPI, angleSpan } from '@ue-too/math';
|
|
133
|
+
|
|
134
|
+
// Normalize angle to [0, 2π)
|
|
135
|
+
const normalized = normalizeAngleZero2TwoPI(Math.PI * 3); // π
|
|
136
|
+
|
|
137
|
+
// Calculate smallest angle difference
|
|
138
|
+
const diff = angleSpan(fromAngle, toAngle); // Range: (-π, π]
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Comparison Functions
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
import { samePoint, sameDirection, approximatelyTheSame } from '@ue-too/math';
|
|
145
|
+
|
|
146
|
+
// Check if points are approximately equal
|
|
147
|
+
samePoint(a, b); // Uses default precision (0.000001)
|
|
148
|
+
samePoint(a, b, 0.01); // Custom precision
|
|
149
|
+
|
|
150
|
+
// Check if vectors have same direction
|
|
151
|
+
sameDirection(v1, v2);
|
|
152
|
+
|
|
153
|
+
// Approximate number equality
|
|
154
|
+
approximatelyTheSame(1.0, 1.0000001); // true
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Common Use Cases
|
|
158
|
+
|
|
159
|
+
### Canvas Transformations
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
import { PointCal, Point } from '@ue-too/math';
|
|
163
|
+
|
|
164
|
+
// Transform mouse coordinates to rotated canvas space
|
|
165
|
+
const mousePos: Point = { x: 150, y: 200 };
|
|
166
|
+
const canvasCenter: Point = { x: 100, y: 100 };
|
|
167
|
+
const canvasRotation = Math.PI / 4; // 45 degrees
|
|
168
|
+
|
|
169
|
+
const transformedPos = PointCal.transformPointWRTAnchor(
|
|
170
|
+
mousePos,
|
|
171
|
+
canvasCenter,
|
|
172
|
+
-canvasRotation // Inverse rotation
|
|
173
|
+
);
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Path Following
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
import { PointCal, Point } from '@ue-too/math';
|
|
180
|
+
|
|
181
|
+
// Calculate direction from current position to target
|
|
182
|
+
const current: Point = { x: 10, y: 20 };
|
|
183
|
+
const target: Point = { x: 50, y: 80 };
|
|
184
|
+
|
|
185
|
+
const direction = PointCal.unitVectorFromA2B(current, target);
|
|
186
|
+
const speed = 5;
|
|
187
|
+
|
|
188
|
+
// Move toward target
|
|
189
|
+
const newPosition = PointCal.addVector(
|
|
190
|
+
current,
|
|
191
|
+
PointCal.multiplyVectorByScalar(direction, speed)
|
|
192
|
+
);
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Smooth Interpolation
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
import { PointCal, Point } from '@ue-too/math';
|
|
199
|
+
|
|
200
|
+
// Animate between two positions
|
|
201
|
+
const start: Point = { x: 0, y: 0 };
|
|
202
|
+
const end: Point = { x: 100, y: 100 };
|
|
203
|
+
const progress = 0.3; // 30% through animation
|
|
204
|
+
|
|
205
|
+
const currentPos = PointCal.linearInterpolation(start, end, progress);
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## API Reference
|
|
209
|
+
|
|
210
|
+
For complete API documentation with detailed examples, see:
|
|
211
|
+
- [Full TypeDoc Documentation](../../docs/math) (generated from source)
|
|
212
|
+
- [Source Code](./src/index.ts) with inline JSDoc comments
|
|
213
|
+
|
|
214
|
+
## TypeScript Support
|
|
215
|
+
|
|
216
|
+
This package is written in TypeScript and includes full type definitions:
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
import { Point, PointCal } from '@ue-too/math';
|
|
220
|
+
|
|
221
|
+
const point: Point = { x: 10, y: 20 }; // z is optional
|
|
222
|
+
const point3d: Point = { x: 10, y: 20, z: 30 };
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Performance Considerations
|
|
226
|
+
|
|
227
|
+
- All operations are pure functions with no side effects
|
|
228
|
+
- Static methods minimize object allocation overhead
|
|
229
|
+
- Suitable for tight animation loops (60fps)
|
|
230
|
+
- For performance-critical code, consider using the operations directly rather than chaining
|
|
231
|
+
|
|
232
|
+
### Performance Tips
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
// ✅ Good: Single operation
|
|
236
|
+
const mag = PointCal.magnitude(vector);
|
|
237
|
+
|
|
238
|
+
// ⚠️ Less optimal: Multiple magnitude calls
|
|
239
|
+
const unit = PointCal.unitVector(vector); // Calls magnitude twice internally
|
|
240
|
+
|
|
241
|
+
// ✅ Better: Calculate magnitude once if needed separately
|
|
242
|
+
const mag = PointCal.magnitude(vector);
|
|
243
|
+
const unit = PointCal.divideVectorByScalar(vector, mag);
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Related Packages
|
|
247
|
+
|
|
248
|
+
- [`@ue-too/board`](../board) - Canvas viewport management with pan, zoom, rotate
|
|
249
|
+
- [`@ue-too/animate`](../animate) - Animation system using these math utilities
|
|
250
|
+
- [`@ue-too/dynamics`](../dynamics) - Physics engine built on these operations
|
|
251
|
+
|
|
252
|
+
## License
|
|
253
|
+
|
|
254
|
+
MIT License - see [LICENSE.txt](../../LICENSE.txt) for details.
|
|
255
|
+
|
|
256
|
+
## Contributing
|
|
257
|
+
|
|
258
|
+
> Currently not accepting contributions. If you have feature requests or bug reports, please [create an issue](https://github.com/ue-too/ue-too/issues).
|
package/index.d.ts
CHANGED
|
@@ -1,34 +1,533 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @packageDocumentation
|
|
3
|
+
* Mathematical utilities for 2D and 3D point operations, vector calculations, and transformations.
|
|
4
|
+
*
|
|
5
|
+
* @remarks
|
|
6
|
+
* This package provides essential mathematical operations for canvas applications including:
|
|
7
|
+
* - Vector arithmetic (add, subtract, multiply, divide)
|
|
8
|
+
* - Vector operations (dot product, cross product, magnitude, unit vectors)
|
|
9
|
+
* - Geometric transformations (rotation, axis transformation)
|
|
10
|
+
* - Angle calculations and normalization
|
|
11
|
+
* - Point comparisons and interpolation
|
|
12
|
+
* - Line intersection detection
|
|
13
|
+
*
|
|
14
|
+
* All operations support both 2D and 3D coordinates, with the z-axis being optional.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* Basic vector operations
|
|
18
|
+
* ```typescript
|
|
19
|
+
* import { PointCal, Point } from '@ue-too/math';
|
|
20
|
+
*
|
|
21
|
+
* const a: Point = { x: 1, y: 2 };
|
|
22
|
+
* const b: Point = { x: 3, y: 4 };
|
|
23
|
+
*
|
|
24
|
+
* // Add vectors
|
|
25
|
+
* const sum = PointCal.addVector(a, b); // { x: 4, y: 6 }
|
|
26
|
+
*
|
|
27
|
+
* // Calculate magnitude
|
|
28
|
+
* const mag = PointCal.magnitude(a); // 2.236...
|
|
29
|
+
*
|
|
30
|
+
* // Get unit vector
|
|
31
|
+
* const unit = PointCal.unitVector(a); // { x: 0.447..., y: 0.894... }
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* Rotation and transformation
|
|
36
|
+
* ```typescript
|
|
37
|
+
* import { PointCal, Point } from '@ue-too/math';
|
|
38
|
+
*
|
|
39
|
+
* const point: Point = { x: 10, y: 0 };
|
|
40
|
+
* const angle = Math.PI / 2; // 90 degrees
|
|
41
|
+
*
|
|
42
|
+
* // Rotate point around origin
|
|
43
|
+
* const rotated = PointCal.rotatePoint(point, angle); // { x: 0, y: 10 }
|
|
44
|
+
*
|
|
45
|
+
* // Rotate around a custom anchor
|
|
46
|
+
* const anchor: Point = { x: 5, y: 5 };
|
|
47
|
+
* const rotatedAroundAnchor = PointCal.transformPointWRTAnchor(point, anchor, angle);
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
/**
|
|
51
|
+
* Represents a 2D or 3D point with optional z-coordinate.
|
|
52
|
+
*
|
|
53
|
+
* @remarks
|
|
54
|
+
* This is a lowercase variant maintained for backward compatibility.
|
|
55
|
+
* Use {@link Point} for new code.
|
|
56
|
+
*
|
|
57
|
+
* @deprecated Use {@link Point} instead for better TypeScript conventions.
|
|
58
|
+
*/
|
|
1
59
|
export type point = {
|
|
60
|
+
/** X-coordinate */
|
|
2
61
|
x: number;
|
|
62
|
+
/** Y-coordinate */
|
|
3
63
|
y: number;
|
|
64
|
+
/** Optional Z-coordinate for 3D operations */
|
|
4
65
|
z?: number;
|
|
5
66
|
};
|
|
67
|
+
/**
|
|
68
|
+
* Represents a 2D or 3D point with optional z-coordinate.
|
|
69
|
+
*
|
|
70
|
+
* @remarks
|
|
71
|
+
* When z is undefined, operations treat the point as 2D (z = 0).
|
|
72
|
+
* This type is used throughout the library for all point and vector operations.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```typescript
|
|
76
|
+
* // 2D point
|
|
77
|
+
* const p2d: Point = { x: 10, y: 20 };
|
|
78
|
+
*
|
|
79
|
+
* // 3D point
|
|
80
|
+
* const p3d: Point = { x: 10, y: 20, z: 30 };
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
6
83
|
export type Point = {
|
|
84
|
+
/** X-coordinate */
|
|
7
85
|
x: number;
|
|
86
|
+
/** Y-coordinate */
|
|
8
87
|
y: number;
|
|
88
|
+
/** Optional Z-coordinate for 3D operations */
|
|
9
89
|
z?: number;
|
|
10
90
|
};
|
|
91
|
+
/**
|
|
92
|
+
* Utility class for point and vector calculations.
|
|
93
|
+
*
|
|
94
|
+
* @remarks
|
|
95
|
+
* PointCal provides static methods for common 2D and 3D mathematical operations
|
|
96
|
+
* used in canvas applications. All methods handle both 2D and 3D coordinates seamlessly.
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* import { PointCal, Point } from '@ue-too/math';
|
|
101
|
+
*
|
|
102
|
+
* const v1: Point = { x: 1, y: 2 };
|
|
103
|
+
* const v2: Point = { x: 3, y: 4 };
|
|
104
|
+
*
|
|
105
|
+
* const sum = PointCal.addVector(v1, v2);
|
|
106
|
+
* const dot = PointCal.dotProduct(v1, v2);
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
11
109
|
export declare class PointCal {
|
|
110
|
+
/**
|
|
111
|
+
* Adds two vectors together.
|
|
112
|
+
*
|
|
113
|
+
* @param a - First vector
|
|
114
|
+
* @param b - Second vector
|
|
115
|
+
* @returns The sum of vectors a and b
|
|
116
|
+
*
|
|
117
|
+
* @remarks
|
|
118
|
+
* If either vector lacks a z-coordinate, it's treated as 0.
|
|
119
|
+
* The result will include a z-coordinate if either input has one.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```typescript
|
|
123
|
+
* const a = { x: 1, y: 2 };
|
|
124
|
+
* const b = { x: 3, y: 4 };
|
|
125
|
+
* const sum = PointCal.addVector(a, b); // { x: 4, y: 6 }
|
|
126
|
+
*
|
|
127
|
+
* // With 3D coordinates
|
|
128
|
+
* const a3d = { x: 1, y: 2, z: 3 };
|
|
129
|
+
* const b3d = { x: 4, y: 5, z: 6 };
|
|
130
|
+
* const sum3d = PointCal.addVector(a3d, b3d); // { x: 5, y: 7, z: 9 }
|
|
131
|
+
* ```
|
|
132
|
+
*
|
|
133
|
+
* @group Vector Arithmetic
|
|
134
|
+
*/
|
|
12
135
|
static addVector(a: point, b: point): Point;
|
|
136
|
+
/**
|
|
137
|
+
* Subtracts vector b from vector a.
|
|
138
|
+
*
|
|
139
|
+
* @param a - Vector to subtract from
|
|
140
|
+
* @param b - Vector to subtract
|
|
141
|
+
* @returns The difference (a - b)
|
|
142
|
+
*
|
|
143
|
+
* @remarks
|
|
144
|
+
* If either vector lacks a z-coordinate, it's treated as 0.
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```typescript
|
|
148
|
+
* const a = { x: 5, y: 7 };
|
|
149
|
+
* const b = { x: 2, y: 3 };
|
|
150
|
+
* const diff = PointCal.subVector(a, b); // { x: 3, y: 4 }
|
|
151
|
+
* ```
|
|
152
|
+
*
|
|
153
|
+
* @group Vector Arithmetic
|
|
154
|
+
*/
|
|
13
155
|
static subVector(a: point, b: point): Point;
|
|
156
|
+
/**
|
|
157
|
+
* Multiplies a vector by a scalar value.
|
|
158
|
+
*
|
|
159
|
+
* @param a - Vector to multiply
|
|
160
|
+
* @param b - Scalar multiplier
|
|
161
|
+
* @returns The scaled vector
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```typescript
|
|
165
|
+
* const v = { x: 2, y: 3 };
|
|
166
|
+
* const scaled = PointCal.multiplyVectorByScalar(v, 2.5); // { x: 5, y: 7.5 }
|
|
167
|
+
* ```
|
|
168
|
+
*
|
|
169
|
+
* @group Vector Arithmetic
|
|
170
|
+
*/
|
|
14
171
|
static multiplyVectorByScalar(a: point, b: number): Point;
|
|
172
|
+
/**
|
|
173
|
+
* Divides a vector by a scalar value.
|
|
174
|
+
*
|
|
175
|
+
* @param a - Vector to divide
|
|
176
|
+
* @param b - Scalar divisor
|
|
177
|
+
* @returns The divided vector, or the original vector if b is 0
|
|
178
|
+
*
|
|
179
|
+
* @remarks
|
|
180
|
+
* Division by zero returns the original vector unchanged to prevent NaN values.
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* const v = { x: 10, y: 20 };
|
|
185
|
+
* const divided = PointCal.divideVectorByScalar(v, 2); // { x: 5, y: 10 }
|
|
186
|
+
* ```
|
|
187
|
+
*
|
|
188
|
+
* @group Vector Arithmetic
|
|
189
|
+
*/
|
|
15
190
|
static divideVectorByScalar(a: point, b: number): Point;
|
|
191
|
+
/**
|
|
192
|
+
* Calculates the magnitude (length) of a vector.
|
|
193
|
+
*
|
|
194
|
+
* @param a - Vector to measure
|
|
195
|
+
* @returns The magnitude of the vector
|
|
196
|
+
*
|
|
197
|
+
* @remarks
|
|
198
|
+
* Uses the Euclidean distance formula: √(x² + y² + z²)
|
|
199
|
+
*
|
|
200
|
+
* @example
|
|
201
|
+
* ```typescript
|
|
202
|
+
* const v = { x: 3, y: 4 };
|
|
203
|
+
* const mag = PointCal.magnitude(v); // 5
|
|
204
|
+
*
|
|
205
|
+
* const v3d = { x: 1, y: 2, z: 2 };
|
|
206
|
+
* const mag3d = PointCal.magnitude(v3d); // 3
|
|
207
|
+
* ```
|
|
208
|
+
*
|
|
209
|
+
* @group Vector Operations
|
|
210
|
+
*/
|
|
16
211
|
static magnitude(a: point): number;
|
|
212
|
+
/**
|
|
213
|
+
* Converts a vector to its unit vector (normalized to length 1).
|
|
214
|
+
*
|
|
215
|
+
* @param a - Vector to normalize
|
|
216
|
+
* @returns Unit vector in the same direction, or zero vector if magnitude is 0
|
|
217
|
+
*
|
|
218
|
+
* @remarks
|
|
219
|
+
* A unit vector has magnitude 1 and preserves the original direction.
|
|
220
|
+
* Returns {x: 0, y: 0, z: 0} if the input vector has zero magnitude.
|
|
221
|
+
*
|
|
222
|
+
* **Performance note**: This method calls `magnitude()` twice. For better performance
|
|
223
|
+
* when you need both magnitude and unit vector, calculate magnitude once and divide manually.
|
|
224
|
+
*
|
|
225
|
+
* @example
|
|
226
|
+
* ```typescript
|
|
227
|
+
* const v = { x: 3, y: 4 };
|
|
228
|
+
* const unit = PointCal.unitVector(v); // { x: 0.6, y: 0.8 }
|
|
229
|
+
* ```
|
|
230
|
+
*
|
|
231
|
+
* @group Vector Operations
|
|
232
|
+
*/
|
|
17
233
|
static unitVector(a: point): Point;
|
|
234
|
+
/**
|
|
235
|
+
* Calculates the dot product of two vectors.
|
|
236
|
+
*
|
|
237
|
+
* @param a - First vector
|
|
238
|
+
* @param b - Second vector
|
|
239
|
+
* @returns The dot product (scalar value)
|
|
240
|
+
*
|
|
241
|
+
* @remarks
|
|
242
|
+
* The dot product is: a.x * b.x + a.y * b.y + a.z * b.z
|
|
243
|
+
*
|
|
244
|
+
* **Use cases:**
|
|
245
|
+
* - Determine if vectors are perpendicular (dot = 0)
|
|
246
|
+
* - Calculate angle between vectors: θ = acos(dot / (|a| * |b|))
|
|
247
|
+
* - Project one vector onto another
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* ```typescript
|
|
251
|
+
* const a = { x: 1, y: 0 };
|
|
252
|
+
* const b = { x: 0, y: 1 };
|
|
253
|
+
* const dot = PointCal.dotProduct(a, b); // 0 (perpendicular vectors)
|
|
254
|
+
*
|
|
255
|
+
* const c = { x: 2, y: 3 };
|
|
256
|
+
* const d = { x: 4, y: 5 };
|
|
257
|
+
* const dot2 = PointCal.dotProduct(c, d); // 23
|
|
258
|
+
* ```
|
|
259
|
+
*
|
|
260
|
+
* @group Vector Operations
|
|
261
|
+
*/
|
|
18
262
|
static dotProduct(a: point, b: point): number;
|
|
263
|
+
/**
|
|
264
|
+
* Calculates the cross product of two vectors.
|
|
265
|
+
*
|
|
266
|
+
* @param a - First vector
|
|
267
|
+
* @param b - Second vector
|
|
268
|
+
* @returns The cross product vector perpendicular to both inputs
|
|
269
|
+
*
|
|
270
|
+
* @remarks
|
|
271
|
+
* The cross product is perpendicular to both input vectors, following the right-hand rule.
|
|
272
|
+
* For 2D vectors (z undefined), z is treated as 0.
|
|
273
|
+
*
|
|
274
|
+
* **Properties:**
|
|
275
|
+
* - Result is perpendicular to both input vectors
|
|
276
|
+
* - Magnitude equals area of parallelogram formed by vectors
|
|
277
|
+
* - Direction follows right-hand rule
|
|
278
|
+
*
|
|
279
|
+
* @example
|
|
280
|
+
* ```typescript
|
|
281
|
+
* const a = { x: 1, y: 0, z: 0 };
|
|
282
|
+
* const b = { x: 0, y: 1, z: 0 };
|
|
283
|
+
* const cross = PointCal.crossProduct(a, b); // { x: 0, y: 0, z: 1 }
|
|
284
|
+
* ```
|
|
285
|
+
*
|
|
286
|
+
* @group Vector Operations
|
|
287
|
+
*/
|
|
19
288
|
static crossProduct(a: point, b: point): Point;
|
|
289
|
+
/**
|
|
290
|
+
* Calculates the unit vector pointing from point a to point b.
|
|
291
|
+
*
|
|
292
|
+
* @param a - Starting point
|
|
293
|
+
* @param b - Ending point
|
|
294
|
+
* @returns Unit vector in the direction from a to b
|
|
295
|
+
*
|
|
296
|
+
* @remarks
|
|
297
|
+
* Equivalent to calling unitVector(subVector(b, a))
|
|
298
|
+
*
|
|
299
|
+
* @example
|
|
300
|
+
* ```typescript
|
|
301
|
+
* const a = { x: 0, y: 0 };
|
|
302
|
+
* const b = { x: 3, y: 4 };
|
|
303
|
+
* const direction = PointCal.unitVectorFromA2B(a, b); // { x: 0.6, y: 0.8 }
|
|
304
|
+
* ```
|
|
305
|
+
*
|
|
306
|
+
* @group Geometric Calculations
|
|
307
|
+
*/
|
|
20
308
|
static unitVectorFromA2B(a: point, b: point): Point;
|
|
309
|
+
/**
|
|
310
|
+
* Rotates a point around the origin.
|
|
311
|
+
*
|
|
312
|
+
* @param point - Point to rotate
|
|
313
|
+
* @param angle - Rotation angle in radians (counter-clockwise)
|
|
314
|
+
* @returns Rotated point
|
|
315
|
+
*
|
|
316
|
+
* @remarks
|
|
317
|
+
* Rotation is performed around the origin (0, 0).
|
|
318
|
+
* Positive angles rotate counter-clockwise, negative angles rotate clockwise.
|
|
319
|
+
* For rotation around a custom anchor, use {@link transformPointWRTAnchor}.
|
|
320
|
+
*
|
|
321
|
+
* **Performance**: Uses trigonometric functions (sin/cos). For many rotations with
|
|
322
|
+
* the same angle, pre-calculate sin/cos values and apply the transformation manually.
|
|
323
|
+
*
|
|
324
|
+
* @example
|
|
325
|
+
* ```typescript
|
|
326
|
+
* const point = { x: 1, y: 0 };
|
|
327
|
+
* const rotated = PointCal.rotatePoint(point, Math.PI / 2); // { x: 0, y: 1 }
|
|
328
|
+
* ```
|
|
329
|
+
*
|
|
330
|
+
* @group Transformations
|
|
331
|
+
*/
|
|
21
332
|
static rotatePoint(point: point, angle: number): Point;
|
|
333
|
+
/**
|
|
334
|
+
* Transforms a point's coordinates to a new rotated axis system.
|
|
335
|
+
*
|
|
336
|
+
* @param point - Point in original coordinate system
|
|
337
|
+
* @param angleFromOriginalAxis2DestAxis - Rotation angle from original to destination axis (radians, CCW positive)
|
|
338
|
+
* @returns Point coordinates in the new axis system
|
|
339
|
+
*
|
|
340
|
+
* @remarks
|
|
341
|
+
* This performs an axis rotation transformation, converting coordinates from one
|
|
342
|
+
* reference frame to another rotated by the specified angle.
|
|
343
|
+
*
|
|
344
|
+
* @example
|
|
345
|
+
* ```typescript
|
|
346
|
+
* const point = { x: 10, y: 0 };
|
|
347
|
+
* const angle = Math.PI / 4; // 45 degrees
|
|
348
|
+
* const transformed = PointCal.transform2NewAxis(point, angle);
|
|
349
|
+
* ```
|
|
350
|
+
*
|
|
351
|
+
* @group Transformations
|
|
352
|
+
*/
|
|
22
353
|
static transform2NewAxis(point: point, angleFromOriginalAxis2DestAxis: number): Point;
|
|
23
354
|
/**
|
|
24
|
-
*
|
|
355
|
+
* Calculates the signed angle from vector a to vector b.
|
|
356
|
+
*
|
|
357
|
+
* @param a - First vector (starting direction)
|
|
358
|
+
* @param b - Second vector (ending direction)
|
|
359
|
+
* @returns The signed angle in radians, range: (-π, π]
|
|
360
|
+
*
|
|
361
|
+
* @remarks
|
|
362
|
+
* - Positive angles indicate counter-clockwise rotation from a to b
|
|
363
|
+
* - Negative angles indicate clockwise rotation from a to b
|
|
364
|
+
* - Uses atan2 for proper quadrant handling
|
|
365
|
+
*
|
|
366
|
+
* @example
|
|
367
|
+
* ```typescript
|
|
368
|
+
* const right = { x: 1, y: 0 };
|
|
369
|
+
* const up = { x: 0, y: 1 };
|
|
370
|
+
* const angle = PointCal.angleFromA2B(right, up); // π/2 (90 degrees CCW)
|
|
371
|
+
*
|
|
372
|
+
* const down = { x: 0, y: -1 };
|
|
373
|
+
* const angleDown = PointCal.angleFromA2B(right, down); // -π/2 (90 degrees CW)
|
|
374
|
+
* ```
|
|
375
|
+
*
|
|
376
|
+
* @group Angle Utilities
|
|
25
377
|
*/
|
|
26
378
|
static angleFromA2B(a: point, b: point): number;
|
|
379
|
+
/**
|
|
380
|
+
* Rotates a point around a custom anchor point.
|
|
381
|
+
*
|
|
382
|
+
* @param point - Point to rotate
|
|
383
|
+
* @param anchor - Anchor point to rotate around
|
|
384
|
+
* @param angle - Rotation angle in radians (counter-clockwise)
|
|
385
|
+
* @returns Rotated point
|
|
386
|
+
*
|
|
387
|
+
* @remarks
|
|
388
|
+
* This is equivalent to:
|
|
389
|
+
* 1. Translate point by -anchor
|
|
390
|
+
* 2. Rotate around origin
|
|
391
|
+
* 3. Translate back by +anchor
|
|
392
|
+
*
|
|
393
|
+
* @example
|
|
394
|
+
* ```typescript
|
|
395
|
+
* const point = { x: 10, y: 5 };
|
|
396
|
+
* const anchor = { x: 5, y: 5 };
|
|
397
|
+
* const angle = Math.PI / 2; // 90 degrees
|
|
398
|
+
* const rotated = PointCal.transformPointWRTAnchor(point, anchor, angle);
|
|
399
|
+
* // Rotates point around anchor (5, 5)
|
|
400
|
+
* ```
|
|
401
|
+
*
|
|
402
|
+
* @group Transformations
|
|
403
|
+
*/
|
|
27
404
|
static transformPointWRTAnchor(point: point, anchor: point, angle: number): Point;
|
|
405
|
+
/**
|
|
406
|
+
* Calculates the Euclidean distance between two points.
|
|
407
|
+
*
|
|
408
|
+
* @param a - First point
|
|
409
|
+
* @param b - Second point
|
|
410
|
+
* @returns The distance between the two points
|
|
411
|
+
*
|
|
412
|
+
* @remarks
|
|
413
|
+
* Equivalent to calculating the magnitude of the vector from a to b.
|
|
414
|
+
*
|
|
415
|
+
* @example
|
|
416
|
+
* ```typescript
|
|
417
|
+
* const a = { x: 0, y: 0 };
|
|
418
|
+
* const b = { x: 3, y: 4 };
|
|
419
|
+
* const distance = PointCal.distanceBetweenPoints(a, b); // 5
|
|
420
|
+
* ```
|
|
421
|
+
*
|
|
422
|
+
* @group Geometric Calculations
|
|
423
|
+
*/
|
|
28
424
|
static distanceBetweenPoints(a: point, b: point): number;
|
|
425
|
+
/**
|
|
426
|
+
* Flips a point's y-coordinate (mirrors across the x-axis).
|
|
427
|
+
*
|
|
428
|
+
* @param point - Point to flip
|
|
429
|
+
* @returns Point with negated y-coordinate
|
|
430
|
+
*
|
|
431
|
+
* @remarks
|
|
432
|
+
* Useful for converting between coordinate systems where the y-axis direction differs.
|
|
433
|
+
* Common when converting between screen coordinates (y-down) and mathematical coordinates (y-up).
|
|
434
|
+
*
|
|
435
|
+
* @example
|
|
436
|
+
* ```typescript
|
|
437
|
+
* const point = { x: 10, y: 20 };
|
|
438
|
+
* const flipped = PointCal.flipYAxis(point); // { x: 10, y: -20 }
|
|
439
|
+
* ```
|
|
440
|
+
*
|
|
441
|
+
* @group Transformations
|
|
442
|
+
*/
|
|
29
443
|
static flipYAxis(point: point): Point;
|
|
444
|
+
/**
|
|
445
|
+
* Performs linear interpolation between two points.
|
|
446
|
+
*
|
|
447
|
+
* @param a - Starting point (t = 0)
|
|
448
|
+
* @param b - Ending point (t = 1)
|
|
449
|
+
* @param t - Interpolation parameter (0 to 1)
|
|
450
|
+
* @returns Interpolated point
|
|
451
|
+
*
|
|
452
|
+
* @remarks
|
|
453
|
+
* - t = 0 returns point a
|
|
454
|
+
* - t = 1 returns point b
|
|
455
|
+
* - t = 0.5 returns the midpoint
|
|
456
|
+
* - Values outside [0, 1] perform extrapolation
|
|
457
|
+
*
|
|
458
|
+
* **Performance**: Suitable for animation loops and real-time interpolation.
|
|
459
|
+
*
|
|
460
|
+
* @example
|
|
461
|
+
* ```typescript
|
|
462
|
+
* const a = { x: 0, y: 0 };
|
|
463
|
+
* const b = { x: 10, y: 20 };
|
|
464
|
+
* const mid = PointCal.linearInterpolation(a, b, 0.5); // { x: 5, y: 10 }
|
|
465
|
+
* const quarter = PointCal.linearInterpolation(a, b, 0.25); // { x: 2.5, y: 5 }
|
|
466
|
+
* ```
|
|
467
|
+
*
|
|
468
|
+
* @group Geometric Calculations
|
|
469
|
+
*/
|
|
30
470
|
static linearInterpolation(a: point, b: point, t: number): point;
|
|
471
|
+
/**
|
|
472
|
+
* Checks if two points are exactly equal.
|
|
473
|
+
*
|
|
474
|
+
* @param a - First point
|
|
475
|
+
* @param b - Second point
|
|
476
|
+
* @returns True if all coordinates are exactly equal
|
|
477
|
+
*
|
|
478
|
+
* @remarks
|
|
479
|
+
* Uses strict equality (===) for comparison.
|
|
480
|
+
* For approximate equality with tolerance, use {@link samePoint} instead.
|
|
481
|
+
* Missing z-coordinates are treated as 0.
|
|
482
|
+
*
|
|
483
|
+
* @example
|
|
484
|
+
* ```typescript
|
|
485
|
+
* const a = { x: 1, y: 2 };
|
|
486
|
+
* const b = { x: 1, y: 2 };
|
|
487
|
+
* PointCal.isEqual(a, b); // true
|
|
488
|
+
*
|
|
489
|
+
* const c = { x: 1.0000001, y: 2 };
|
|
490
|
+
* PointCal.isEqual(a, c); // false (use samePoint for tolerance)
|
|
491
|
+
* ```
|
|
492
|
+
*
|
|
493
|
+
* @group Geometric Calculations
|
|
494
|
+
*/
|
|
31
495
|
static isEqual(a: point, b: point): boolean;
|
|
496
|
+
/**
|
|
497
|
+
* Calculates the intersection point of two line segments.
|
|
498
|
+
*
|
|
499
|
+
* @param startPoint - Start of first line segment
|
|
500
|
+
* @param endPoint - End of first line segment
|
|
501
|
+
* @param startPoint2 - Start of second line segment
|
|
502
|
+
* @param endPoint2 - End of second line segment
|
|
503
|
+
* @returns Object containing intersection status and details
|
|
504
|
+
*
|
|
505
|
+
* @remarks
|
|
506
|
+
* Returns an object with:
|
|
507
|
+
* - `intersects`: Boolean indicating if segments intersect
|
|
508
|
+
* - `intersection`: The intersection point (only if intersects is true)
|
|
509
|
+
* - `offset`: Parameter t where intersection occurs on first segment (0 to 1)
|
|
510
|
+
*
|
|
511
|
+
* The segments must actually cross within their bounds (not just their infinite extensions).
|
|
512
|
+
*
|
|
513
|
+
* **Use cases:**
|
|
514
|
+
* - Collision detection between line segments
|
|
515
|
+
* - Ray casting and visibility checks
|
|
516
|
+
* - Path intersection detection
|
|
517
|
+
*
|
|
518
|
+
* @example
|
|
519
|
+
* ```typescript
|
|
520
|
+
* const line1Start = { x: 0, y: 0 };
|
|
521
|
+
* const line1End = { x: 10, y: 10 };
|
|
522
|
+
* const line2Start = { x: 0, y: 10 };
|
|
523
|
+
* const line2End = { x: 10, y: 0 };
|
|
524
|
+
*
|
|
525
|
+
* const result = PointCal.getLineIntersection(line1Start, line1End, line2Start, line2End);
|
|
526
|
+
* // { intersects: true, intersection: { x: 5, y: 5 }, offset: 0.5 }
|
|
527
|
+
* ```
|
|
528
|
+
*
|
|
529
|
+
* @group Geometric Calculations
|
|
530
|
+
*/
|
|
32
531
|
static getLineIntersection(startPoint: Point, endPoint: Point, startPoint2: Point, endPoint2: Point): {
|
|
33
532
|
intersects: boolean;
|
|
34
533
|
intersection?: Point;
|
|
@@ -36,18 +535,143 @@ export declare class PointCal {
|
|
|
36
535
|
};
|
|
37
536
|
}
|
|
38
537
|
/**
|
|
39
|
-
*
|
|
538
|
+
* Normalizes an angle to the range [0, 2π).
|
|
539
|
+
*
|
|
540
|
+
* @param angle - Angle in radians (can be any value)
|
|
541
|
+
* @returns Normalized angle between 0 and 2π
|
|
542
|
+
*
|
|
543
|
+
* @remarks
|
|
544
|
+
* This function wraps any angle to the range [0, 2π) by taking the modulo
|
|
545
|
+
* and ensuring the result is positive.
|
|
40
546
|
*
|
|
41
|
-
* @
|
|
547
|
+
* @example
|
|
548
|
+
* ```typescript
|
|
549
|
+
* normalizeAngleZero2TwoPI(Math.PI * 3); // π (180 degrees)
|
|
550
|
+
* normalizeAngleZero2TwoPI(-Math.PI / 2); // 3π/2 (270 degrees)
|
|
551
|
+
* normalizeAngleZero2TwoPI(0); // 0
|
|
552
|
+
* ```
|
|
553
|
+
*
|
|
554
|
+
* @category Angle
|
|
42
555
|
*/
|
|
43
556
|
export declare function normalizeAngleZero2TwoPI(angle: number): number;
|
|
44
557
|
/**
|
|
45
|
-
*
|
|
558
|
+
* Calculates the smallest angular difference between two angles.
|
|
559
|
+
*
|
|
560
|
+
* @param from - Starting angle in radians
|
|
561
|
+
* @param to - Ending angle in radians
|
|
562
|
+
* @returns The smallest angle span from 'from' to 'to', in range (-π, π]
|
|
563
|
+
*
|
|
564
|
+
* @remarks
|
|
565
|
+
* This function accounts for wrapping around 2π and always returns the shorter path.
|
|
566
|
+
* Positive result means counter-clockwise rotation, negative means clockwise.
|
|
46
567
|
*
|
|
47
|
-
* @
|
|
568
|
+
* @example
|
|
569
|
+
* ```typescript
|
|
570
|
+
* // From 0° to 90°
|
|
571
|
+
* angleSpan(0, Math.PI / 2); // π/2 (90 degrees CCW)
|
|
572
|
+
*
|
|
573
|
+
* // From 350° to 10° (shorter to go CCW through 0°)
|
|
574
|
+
* angleSpan(350 * Math.PI / 180, 10 * Math.PI / 180); // ≈ 20 degrees
|
|
575
|
+
*
|
|
576
|
+
* // From 10° to 350° (shorter to go CW through 0°)
|
|
577
|
+
* angleSpan(10 * Math.PI / 180, 350 * Math.PI / 180); // ≈ -20 degrees
|
|
578
|
+
* ```
|
|
579
|
+
*
|
|
580
|
+
* @category Angle
|
|
48
581
|
*/
|
|
49
582
|
export declare function angleSpan(from: number, to: number): number;
|
|
583
|
+
/**
|
|
584
|
+
* Checks if two numbers are approximately equal within a tolerance.
|
|
585
|
+
*
|
|
586
|
+
* @param a - First number
|
|
587
|
+
* @param b - Second number
|
|
588
|
+
* @param precision - Optional tolerance (defaults to 0.000001)
|
|
589
|
+
* @returns True if the absolute difference is within the precision threshold
|
|
590
|
+
*
|
|
591
|
+
* @remarks
|
|
592
|
+
* Useful for floating-point comparisons where exact equality is unreliable.
|
|
593
|
+
*
|
|
594
|
+
* @example
|
|
595
|
+
* ```typescript
|
|
596
|
+
* approximatelyTheSame(1.0, 1.0000001); // true (within default epsilon)
|
|
597
|
+
* approximatelyTheSame(1.0, 1.1); // false
|
|
598
|
+
* approximatelyTheSame(1.0, 1.01, 0.02); // true (within custom precision)
|
|
599
|
+
* ```
|
|
600
|
+
*
|
|
601
|
+
* @category Comparison
|
|
602
|
+
*/
|
|
50
603
|
export declare function approximatelyTheSame(a: number, b: number, precision?: number): boolean;
|
|
604
|
+
/**
|
|
605
|
+
* Checks if two vectors point in the same direction.
|
|
606
|
+
*
|
|
607
|
+
* @param a - First vector
|
|
608
|
+
* @param b - Second vector
|
|
609
|
+
* @param precision - Tolerance for comparison (defaults to 0.001)
|
|
610
|
+
* @returns True if vectors have the same direction (after normalization)
|
|
611
|
+
*
|
|
612
|
+
* @remarks
|
|
613
|
+
* Normalizes both vectors to unit vectors and compares them.
|
|
614
|
+
* Magnitude does not matter, only direction.
|
|
615
|
+
*
|
|
616
|
+
* @example
|
|
617
|
+
* ```typescript
|
|
618
|
+
* const a = { x: 1, y: 0 };
|
|
619
|
+
* const b = { x: 10, y: 0 }; // Same direction, different magnitude
|
|
620
|
+
* sameDirection(a, b); // true
|
|
621
|
+
*
|
|
622
|
+
* const c = { x: 1, y: 1 };
|
|
623
|
+
* sameDirection(a, c); // false (different direction)
|
|
624
|
+
* ```
|
|
625
|
+
*
|
|
626
|
+
* @category Comparison
|
|
627
|
+
*/
|
|
51
628
|
export declare function sameDirection(a: Point, b: Point, precision?: number): boolean;
|
|
629
|
+
/**
|
|
630
|
+
* Checks if a direction vector is aligned with a tangent vector.
|
|
631
|
+
*
|
|
632
|
+
* @param direction - Direction vector to check
|
|
633
|
+
* @param tangent - Tangent vector reference
|
|
634
|
+
* @returns True if direction aligns with tangent (within 90 degrees)
|
|
635
|
+
*
|
|
636
|
+
* @remarks
|
|
637
|
+
* Returns true if the direction is within 90 degrees of either the tangent
|
|
638
|
+
* or its reverse. Useful for determining if movement is along a path.
|
|
639
|
+
*
|
|
640
|
+
* @example
|
|
641
|
+
* ```typescript
|
|
642
|
+
* const direction = { x: 1, y: 0 };
|
|
643
|
+
* const tangent = { x: 1, y: 0.1 }; // Slightly rotated
|
|
644
|
+
* directionAlignedToTangent(direction, tangent); // true
|
|
645
|
+
*
|
|
646
|
+
* const perpendicular = { x: 0, y: 1 };
|
|
647
|
+
* directionAlignedToTangent(perpendicular, tangent); // false
|
|
648
|
+
* ```
|
|
649
|
+
*
|
|
650
|
+
* @category Comparison
|
|
651
|
+
*/
|
|
52
652
|
export declare function directionAlignedToTangent(direction: Point, tangent: Point): boolean;
|
|
653
|
+
/**
|
|
654
|
+
* Checks if two points are approximately at the same location.
|
|
655
|
+
*
|
|
656
|
+
* @param a - First point
|
|
657
|
+
* @param b - Second point
|
|
658
|
+
* @param precision - Optional tolerance for coordinate comparison
|
|
659
|
+
* @returns True if both x and y coordinates are within precision
|
|
660
|
+
*
|
|
661
|
+
* @remarks
|
|
662
|
+
* Uses {@link approximatelyTheSame} for coordinate comparison.
|
|
663
|
+
* For exact equality, use {@link PointCal.isEqual} instead.
|
|
664
|
+
*
|
|
665
|
+
* @example
|
|
666
|
+
* ```typescript
|
|
667
|
+
* const a = { x: 1.0, y: 2.0 };
|
|
668
|
+
* const b = { x: 1.0000001, y: 2.0000001 };
|
|
669
|
+
* samePoint(a, b); // true (within default precision)
|
|
670
|
+
*
|
|
671
|
+
* const c = { x: 1.1, y: 2.0 };
|
|
672
|
+
* samePoint(a, c); // false
|
|
673
|
+
* ```
|
|
674
|
+
*
|
|
675
|
+
* @category Comparison
|
|
676
|
+
*/
|
|
53
677
|
export declare function samePoint(a: Point, b: Point, precision?: number): boolean;
|
package/index.js
CHANGED
|
@@ -1,175 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
class PointCal {
|
|
3
|
-
static addVector(a, b) {
|
|
4
|
-
if (a.z == null && b.z == null)
|
|
5
|
-
return { x: a.x + b.x, y: a.y + b.y };
|
|
6
|
-
if (a.z == null || b.z == null) {
|
|
7
|
-
if (a.z == null)
|
|
8
|
-
a.z = 0;
|
|
9
|
-
if (b.z == null)
|
|
10
|
-
b.z = 0;
|
|
11
|
-
}
|
|
12
|
-
return { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z };
|
|
13
|
-
}
|
|
14
|
-
static subVector(a, b) {
|
|
15
|
-
if (a.z == null && b.z == null)
|
|
16
|
-
return { x: a.x - b.x, y: a.y - b.y };
|
|
17
|
-
if (a.z == null || b.z == null) {
|
|
18
|
-
if (a.z == null)
|
|
19
|
-
a.z = 0;
|
|
20
|
-
if (b.z == null)
|
|
21
|
-
b.z = 0;
|
|
22
|
-
}
|
|
23
|
-
return { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z };
|
|
24
|
-
}
|
|
25
|
-
static multiplyVectorByScalar(a, b) {
|
|
26
|
-
if (a.z == null)
|
|
27
|
-
return { x: a.x * b, y: a.y * b };
|
|
28
|
-
return { x: a.x * b, y: a.y * b, z: a.z * b };
|
|
29
|
-
}
|
|
30
|
-
static divideVectorByScalar(a, b) {
|
|
31
|
-
if (b == 0)
|
|
32
|
-
return { x: a.x, y: a.y };
|
|
33
|
-
if (a.z == null)
|
|
34
|
-
return { x: a.x / b, y: a.y / b };
|
|
35
|
-
return { x: a.x / b, y: a.y / b, z: a.z / b };
|
|
36
|
-
}
|
|
37
|
-
static magnitude(a) {
|
|
38
|
-
if (a.z == null)
|
|
39
|
-
a.z = 0;
|
|
40
|
-
return Math.sqrt(a.x * a.x + a.y * a.y + a.z * a.z);
|
|
41
|
-
}
|
|
42
|
-
static unitVector(a) {
|
|
43
|
-
if (a.z == null)
|
|
44
|
-
a.z = 0;
|
|
45
|
-
return this.magnitude(a) != 0 ? { x: a.x / this.magnitude(a), y: a.y / this.magnitude(a), z: a.z / this.magnitude(a) } : { x: 0, y: 0, z: 0 };
|
|
46
|
-
}
|
|
47
|
-
static dotProduct(a, b) {
|
|
48
|
-
if (a.z == null && b.z == null)
|
|
49
|
-
return a.x * b.x + a.y * b.y;
|
|
50
|
-
if (a.z == null || b.z == null) {
|
|
51
|
-
if (a.z == null)
|
|
52
|
-
a.z = 0;
|
|
53
|
-
if (b.z == null)
|
|
54
|
-
b.z = 0;
|
|
55
|
-
}
|
|
56
|
-
return a.x * b.x + a.y * b.y + a.z * b.z;
|
|
57
|
-
}
|
|
58
|
-
static crossProduct(a, b) {
|
|
59
|
-
if (a.z == null || b.z == null) {
|
|
60
|
-
if (a.z == null)
|
|
61
|
-
a.z = 0;
|
|
62
|
-
if (b.z == null)
|
|
63
|
-
b.z = 0;
|
|
64
|
-
}
|
|
65
|
-
return { x: a.y * b.z - a.z * b.y, y: a.z * b.x - a.x * b.z, z: a.x * b.y - a.y * b.x };
|
|
66
|
-
}
|
|
67
|
-
static unitVectorFromA2B(a, b) {
|
|
68
|
-
return this.unitVector(this.subVector(b, a));
|
|
69
|
-
}
|
|
70
|
-
static rotatePoint(point, angle) {
|
|
71
|
-
return { x: point.x * Math.cos(angle) - point.y * Math.sin(angle), y: point.x * Math.sin(angle) + point.y * Math.cos(angle) };
|
|
72
|
-
}
|
|
73
|
-
static transform2NewAxis(point, angleFromOriginalAxis2DestAxis) {
|
|
74
|
-
return { x: point.x * Math.cos(angleFromOriginalAxis2DestAxis) + point.y * Math.sin(angleFromOriginalAxis2DestAxis), y: -point.x * Math.sin(angleFromOriginalAxis2DestAxis) + point.y * Math.cos(angleFromOriginalAxis2DestAxis) };
|
|
75
|
-
}
|
|
76
|
-
static angleFromA2B(a, b) {
|
|
77
|
-
return Math.atan2(a.x * b.y - a.y * b.x, a.x * b.x + a.y * b.y);
|
|
78
|
-
}
|
|
79
|
-
static transformPointWRTAnchor(point, anchor, angle) {
|
|
80
|
-
let newPoint = this.rotatePoint(this.subVector(point, anchor), angle);
|
|
81
|
-
return this.addVector(newPoint, anchor);
|
|
82
|
-
}
|
|
83
|
-
static distanceBetweenPoints(a, b) {
|
|
84
|
-
return this.magnitude(this.subVector(a, b));
|
|
85
|
-
}
|
|
86
|
-
static flipYAxis(point) {
|
|
87
|
-
return { x: point.x, y: -point.y, z: point.z };
|
|
88
|
-
}
|
|
89
|
-
static linearInterpolation(a, b, t) {
|
|
90
|
-
if (a.z == null || b.z == null) {
|
|
91
|
-
return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t };
|
|
92
|
-
} else {
|
|
93
|
-
return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t, z: a.z + (b.z - a.z) * t };
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
static isEqual(a, b) {
|
|
97
|
-
if (a.z == null) {
|
|
98
|
-
a.z = 0;
|
|
99
|
-
}
|
|
100
|
-
if (b.z == null) {
|
|
101
|
-
b.z = 0;
|
|
102
|
-
}
|
|
103
|
-
return a.x == b.x && a.y == b.y && a.z == b.z;
|
|
104
|
-
}
|
|
105
|
-
static getLineIntersection(startPoint, endPoint, startPoint2, endPoint2) {
|
|
106
|
-
const numerator = (endPoint2.x - startPoint2.x) * (startPoint.y - startPoint2.y) - (endPoint2.y - startPoint2.y) * (startPoint.x - startPoint2.x);
|
|
107
|
-
const denominator = (endPoint2.y - startPoint2.y) * (endPoint.x - startPoint.x) - (endPoint2.x - startPoint2.x) * (endPoint.y - startPoint.y);
|
|
108
|
-
if (denominator === 0) {
|
|
109
|
-
return { intersects: false };
|
|
110
|
-
}
|
|
111
|
-
const t = numerator / denominator;
|
|
112
|
-
if (t >= 0 && t <= 1) {
|
|
113
|
-
return {
|
|
114
|
-
intersects: true,
|
|
115
|
-
intersection: PointCal.linearInterpolation(startPoint, endPoint, t),
|
|
116
|
-
offset: t
|
|
117
|
-
};
|
|
118
|
-
} else {
|
|
119
|
-
return {
|
|
120
|
-
intersects: false
|
|
121
|
-
};
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
function normalizeAngleZero2TwoPI(angle) {
|
|
126
|
-
angle = angle % (Math.PI * 2);
|
|
127
|
-
angle = (angle + Math.PI * 2) % (Math.PI * 2);
|
|
128
|
-
return angle;
|
|
129
|
-
}
|
|
130
|
-
function angleSpan(from, to) {
|
|
131
|
-
from = normalizeAngleZero2TwoPI(from);
|
|
132
|
-
to = normalizeAngleZero2TwoPI(to);
|
|
133
|
-
let angleDiff = to - from;
|
|
134
|
-
if (angleDiff > Math.PI) {
|
|
135
|
-
angleDiff = -(Math.PI * 2 - angleDiff);
|
|
136
|
-
}
|
|
137
|
-
if (angleDiff < -Math.PI) {
|
|
138
|
-
angleDiff += Math.PI * 2;
|
|
139
|
-
}
|
|
140
|
-
return angleDiff;
|
|
141
|
-
}
|
|
142
|
-
function approximatelyTheSame(a, b, precision) {
|
|
143
|
-
const epsilon = 0.000001;
|
|
144
|
-
return Math.abs(a - b) <= (precision || epsilon);
|
|
145
|
-
}
|
|
146
|
-
function sameDirection(a, b, precision = 0.001) {
|
|
147
|
-
const aNormalized = PointCal.unitVector(a);
|
|
148
|
-
const bNormalized = PointCal.unitVector(b);
|
|
149
|
-
return samePoint(aNormalized, bNormalized, precision);
|
|
150
|
-
}
|
|
151
|
-
function directionAlignedToTangent(direction, tangent) {
|
|
152
|
-
const directionNormalized = PointCal.unitVector(direction);
|
|
153
|
-
const tangentNormalized = PointCal.unitVector(tangent);
|
|
154
|
-
const reversedTangent = { x: -tangent.x, y: -tangent.y, z: tangent.z };
|
|
155
|
-
const angle = PointCal.angleFromA2B(directionNormalized, tangentNormalized);
|
|
156
|
-
const angle2 = PointCal.angleFromA2B(directionNormalized, reversedTangent);
|
|
157
|
-
return angle < Math.PI / 2 && angle > -Math.PI / 2 && (angle2 > Math.PI / 2 || angle2 < -Math.PI / 2);
|
|
158
|
-
}
|
|
159
|
-
function samePoint(a, b, precision) {
|
|
160
|
-
if (approximatelyTheSame(a.x, b.x, precision) && approximatelyTheSame(a.y, b.y, precision)) {
|
|
161
|
-
return true;
|
|
162
|
-
}
|
|
163
|
-
return false;
|
|
164
|
-
}
|
|
165
|
-
export {
|
|
166
|
-
samePoint,
|
|
167
|
-
sameDirection,
|
|
168
|
-
normalizeAngleZero2TwoPI,
|
|
169
|
-
directionAlignedToTangent,
|
|
170
|
-
approximatelyTheSame,
|
|
171
|
-
angleSpan,
|
|
172
|
-
PointCal
|
|
173
|
-
};
|
|
1
|
+
class J{static addVector(j,B){if(j.z==null&&B.z==null)return{x:j.x+B.x,y:j.y+B.y};if(j.z==null||B.z==null){if(j.z==null)j.z=0;if(B.z==null)B.z=0}return{x:j.x+B.x,y:j.y+B.y,z:j.z+B.z}}static subVector(j,B){if(j.z==null&&B.z==null)return{x:j.x-B.x,y:j.y-B.y};if(j.z==null||B.z==null){if(j.z==null)j.z=0;if(B.z==null)B.z=0}return{x:j.x-B.x,y:j.y-B.y,z:j.z-B.z}}static multiplyVectorByScalar(j,B){if(j.z==null)return{x:j.x*B,y:j.y*B};return{x:j.x*B,y:j.y*B,z:j.z*B}}static divideVectorByScalar(j,B){if(B==0)return{x:j.x,y:j.y};if(j.z==null)return{x:j.x/B,y:j.y/B};return{x:j.x/B,y:j.y/B,z:j.z/B}}static magnitude(j){if(j.z==null)j.z=0;return Math.sqrt(j.x*j.x+j.y*j.y+j.z*j.z)}static unitVector(j){if(j.z==null)j.z=0;return this.magnitude(j)!=0?{x:j.x/this.magnitude(j),y:j.y/this.magnitude(j),z:j.z/this.magnitude(j)}:{x:0,y:0,z:0}}static dotProduct(j,B){if(j.z==null&&B.z==null)return j.x*B.x+j.y*B.y;if(j.z==null||B.z==null){if(j.z==null)j.z=0;if(B.z==null)B.z=0}return j.x*B.x+j.y*B.y+j.z*B.z}static crossProduct(j,B){if(j.z==null||B.z==null){if(j.z==null)j.z=0;if(B.z==null)B.z=0}return{x:j.y*B.z-j.z*B.y,y:j.z*B.x-j.x*B.z,z:j.x*B.y-j.y*B.x}}static unitVectorFromA2B(j,B){return this.unitVector(this.subVector(B,j))}static rotatePoint(j,B){return{x:j.x*Math.cos(B)-j.y*Math.sin(B),y:j.x*Math.sin(B)+j.y*Math.cos(B)}}static transform2NewAxis(j,B){return{x:j.x*Math.cos(B)+j.y*Math.sin(B),y:-j.x*Math.sin(B)+j.y*Math.cos(B)}}static angleFromA2B(j,B){return Math.atan2(j.x*B.y-j.y*B.x,j.x*B.x+j.y*B.y)}static transformPointWRTAnchor(j,B,G){let H=this.rotatePoint(this.subVector(j,B),G);return this.addVector(H,B)}static distanceBetweenPoints(j,B){return this.magnitude(this.subVector(j,B))}static flipYAxis(j){return{x:j.x,y:-j.y,z:j.z}}static linearInterpolation(j,B,G){if(j.z==null||B.z==null)return{x:j.x+(B.x-j.x)*G,y:j.y+(B.y-j.y)*G};else return{x:j.x+(B.x-j.x)*G,y:j.y+(B.y-j.y)*G,z:j.z+(B.z-j.z)*G}}static isEqual(j,B){if(j.z==null)j.z=0;if(B.z==null)B.z=0;return j.x==B.x&&j.y==B.y&&j.z==B.z}static getLineIntersection(j,B,G,H){let L=(H.x-G.x)*(j.y-G.y)-(H.y-G.y)*(j.x-G.x),M=(H.y-G.y)*(B.x-j.x)-(H.x-G.x)*(B.y-j.y);if(M===0)return{intersects:!1};let K=L/M;if(K>=0&&K<=1)return{intersects:!0,intersection:J.linearInterpolation(j,B,K),offset:K};else return{intersects:!1}}}function Q(j){return j=j%(Math.PI*2),j=(j+Math.PI*2)%(Math.PI*2),j}function W(j,B){j=Q(j),B=Q(B);let G=B-j;if(G>Math.PI)G=-(Math.PI*2-G);if(G<-Math.PI)G+=Math.PI*2;return G}function R(j,B,G){return Math.abs(j-B)<=(G||0.000001)}function X(j,B,G=0.001){let H=J.unitVector(j),L=J.unitVector(B);return V(H,L,G)}function Y(j,B){let G=J.unitVector(j),H=J.unitVector(B),L={x:-B.x,y:-B.y,z:B.z},M=J.angleFromA2B(G,H),K=J.angleFromA2B(G,L);return M<Math.PI/2&&M>-Math.PI/2&&(K>Math.PI/2||K<-Math.PI/2)}function V(j,B,G){if(R(j.x,B.x,G)&&R(j.y,B.y,G))return!0;return!1}export{V as samePoint,X as sameDirection,Q as normalizeAngleZero2TwoPI,Y as directionAlignedToTangent,R as approximatelyTheSame,W as angleSpan,J as PointCal};
|
|
174
2
|
|
|
175
|
-
//# debugId=
|
|
3
|
+
//# debugId=E7FBAB931781982464756E2164756E21
|
package/index.js.map
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"export type point = {\n x: number;\n y: number;\n z?: number;\n}\n\nexport type Point = {\n x: number;\n y: number;\n z?: number;\n}\n\n\nexport class PointCal {\n\n static addVector(a: point, b: point): Point {\n if (a.z == null && b.z == null) return {x: a.x + b.x, y: a.y + b.y};\n if (a.z == null || b.z == null) {\n if (a.z == null) a.z = 0;\n if (b.z == null) b.z = 0;\n }\n return {x: a.x + b.x, y: a.y + b.y, z: a.z + b.z}; \n }\n\n static subVector(a: point, b: point): Point {\n if (a.z == null && b.z == null) return {x: a.x - b.x, y: a.y - b.y};\n if (a.z == null || b.z == null) {\n if (a.z == null) a.z = 0;\n if (b.z == null) b.z = 0;\n }\n return {x: a.x - b.x, y: a.y - b.y, z: a.z - b.z};\n }\n\n static multiplyVectorByScalar(a: point, b: number): Point {\n if (a.z == null) return {x: a.x * b, y: a.y * b};\n return {x: a.x * b, y: a.y * b, z: a.z * b};\n }\n\n static divideVectorByScalar(a: point, b: number): Point {\n if (b == 0) return {x: a.x, y: a.y};\n if (a.z == null) return {x: a.x / b, y: a.y / b};\n return {x: a.x / b, y: a.y / b, z: a.z / b};\n }\n\n static magnitude(a: point): number {\n if (a.z == null) a.z = 0;\n return Math.sqrt(a.x * a.x + a.y * a.y + a.z * a.z);\n }\n\n static unitVector(a: point): Point {\n if (a.z == null) a.z = 0;\n return this.magnitude(a) != 0 ? {x: a.x / this.magnitude(a), y: a.y / this.magnitude(a), z: a.z / this.magnitude(a)} : {x: 0, y: 0, z: 0};\n }\n\n static dotProduct(a: point, b: point): number {\n if (a.z == null && b.z == null) return a.x * b.x + a.y * b.y;\n if (a.z == null || b.z == null) {\n if (a.z == null) a.z = 0;\n if (b.z == null) b.z = 0;\n }\n return a.x * b.x + a.y * b.y + a.z * b.z;\n }\n\n static crossProduct(a: point, b: point): Point {\n if (a.z == null || b.z == null) {\n if (a.z == null) a.z = 0;\n if (b.z == null) b.z = 0;\n }\n return {x: a.y * b.z - a.z * b.y, y: a.z * b.x - a.x * b.z, z: a.x * b.y - a.y * b.x};\n }\n\n static unitVectorFromA2B(a: point, b: point): Point {\n return this.unitVector(this.subVector(b, a));\n }\n\n static rotatePoint(point: point, angle: number): Point {\n return {x: point.x * Math.cos(angle) - point.y * Math.sin(angle), y: point.x * Math.sin(angle) + point.y * Math.cos(angle)};\n }\n\n static transform2NewAxis(point: point, angleFromOriginalAxis2DestAxis: number): Point {\n // angle is the angle from the original axis to the destination axis ccw is positive as always\n return {x: point.x * Math.cos(angleFromOriginalAxis2DestAxis) + point.y * Math.sin(angleFromOriginalAxis2DestAxis), y: -point.x * Math.sin(angleFromOriginalAxis2DestAxis) + point.y * Math.cos(angleFromOriginalAxis2DestAxis)};\n }\n\n /**\n * @description Gets the angle from vector a to vector b. (returned angle is always between -π to π)\n */\n static angleFromA2B(a: point, b: point): number {\n return Math.atan2(a.x * b.y - a.y * b.x, a.x * b.x + a.y * b.y);\n }\n\n static transformPointWRTAnchor(point: point, anchor: point, angle: number): Point {\n // angle is in radians\n let newPoint = this.rotatePoint(this.subVector(point, anchor), angle);\n return this.addVector(newPoint, anchor);\n }\n\n static distanceBetweenPoints(a: point, b: point): number {\n return this.magnitude(this.subVector(a, b));\n }\n\n static flipYAxis(point: point): Point{\n return {x: point.x, y: -point.y, z: point.z};\n }\n\n static linearInterpolation(a: point, b: point, t: number): point{\n if (a.z == null || b.z == null) {\n return {x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t};\n } else {\n return {x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t, z: a.z + (b.z - a.z) * t};\n }\n }\n\n static isEqual(a: point, b: point): boolean{\n if (a.z == null){\n a.z = 0;\n }\n if (b.z == null){\n b.z = 0;\n }\n return a.x == b.x && a.y == b.y && a.z == b.z;\n }\n\n static getLineIntersection(startPoint: Point, endPoint: Point, startPoint2: Point, endPoint2: Point):{\n intersects: boolean,\n intersection?: Point,\n offset?: number\n }{\n const numerator = (endPoint2.x - startPoint2.x) * (startPoint.y - startPoint2.y) - (endPoint2.y - startPoint2.y) * (startPoint.x - startPoint2.x);\n const denominator = (endPoint2.y - startPoint2.y) * (endPoint.x - startPoint.x) - (endPoint2.x - startPoint2.x) * (endPoint.y - startPoint.y);\n \n if (denominator === 0){\n return {intersects: false};\n }\n const t = numerator / denominator;\n if (t >= 0 && t <= 1){\n return {\n intersects: true, \n intersection: PointCal.linearInterpolation(startPoint, endPoint, t),\n offset: t\n }\n } else {\n return {\n intersects: false,\n }\n }\n \n }\n \n}\n\n/**\n * @description Normalizes the angle to be between 0 and 2π.\n * \n * @category Camera\n */\nexport function normalizeAngleZero2TwoPI(angle: number){\n // reduce the angle \n angle = angle % (Math.PI * 2);\n\n // force it to be the positive remainder, so that 0 <= angle < 2 * Math.PI \n angle = (angle + Math.PI * 2) % (Math.PI * 2); \n return angle;\n}\n\n/**\n * @description Gets the smaller angle span between two angles. (in radians)\n * \n * @category Camera\n */\nexport function angleSpan(from: number, to: number): number{\n // in radians\n from = normalizeAngleZero2TwoPI(from);\n to = normalizeAngleZero2TwoPI(to);\n let angleDiff = to - from;\n \n if(angleDiff > Math.PI){\n angleDiff = - (Math.PI * 2 - angleDiff);\n }\n\n if(angleDiff < -Math.PI){\n angleDiff += (Math.PI * 2);\n }\n return angleDiff;\n}\n\nexport function approximatelyTheSame(a: number, b: number, precision?: number): boolean {\n const epsilon = 0.000001\n return Math.abs(a - b) <= (precision || epsilon);\n}\n\nexport function sameDirection(a: Point, b: Point, precision: number = 0.001): boolean{\n const aNormalized = PointCal.unitVector(a);\n const bNormalized = PointCal.unitVector(b);\n return samePoint(aNormalized, bNormalized, precision);\n}\n\nexport function directionAlignedToTangent(direction: Point, tangent: Point): boolean {\n const directionNormalized = PointCal.unitVector(direction);\n const tangentNormalized = PointCal.unitVector(tangent);\n const reversedTangent = {x: -tangent.x, y: -tangent.y, z: tangent.z};\n const angle = PointCal.angleFromA2B(directionNormalized, tangentNormalized);\n const angle2 = PointCal.angleFromA2B(directionNormalized, reversedTangent);\n return (angle < Math.PI / 2 && angle > -Math.PI / 2) && (angle2 > Math.PI / 2 || angle2 < -Math.PI / 2);\n}\n\nexport function samePoint(a: Point, b: Point, precision?: number): boolean {\n if(approximatelyTheSame(a.x, b.x, precision) && approximatelyTheSame(a.y, b.y, precision)){\n return true;\n }\n return false;\n}\n"
|
|
5
|
+
"/**\n * @packageDocumentation\n * Mathematical utilities for 2D and 3D point operations, vector calculations, and transformations.\n *\n * @remarks\n * This package provides essential mathematical operations for canvas applications including:\n * - Vector arithmetic (add, subtract, multiply, divide)\n * - Vector operations (dot product, cross product, magnitude, unit vectors)\n * - Geometric transformations (rotation, axis transformation)\n * - Angle calculations and normalization\n * - Point comparisons and interpolation\n * - Line intersection detection\n *\n * All operations support both 2D and 3D coordinates, with the z-axis being optional.\n *\n * @example\n * Basic vector operations\n * ```typescript\n * import { PointCal, Point } from '@ue-too/math';\n *\n * const a: Point = { x: 1, y: 2 };\n * const b: Point = { x: 3, y: 4 };\n *\n * // Add vectors\n * const sum = PointCal.addVector(a, b); // { x: 4, y: 6 }\n *\n * // Calculate magnitude\n * const mag = PointCal.magnitude(a); // 2.236...\n *\n * // Get unit vector\n * const unit = PointCal.unitVector(a); // { x: 0.447..., y: 0.894... }\n * ```\n *\n * @example\n * Rotation and transformation\n * ```typescript\n * import { PointCal, Point } from '@ue-too/math';\n *\n * const point: Point = { x: 10, y: 0 };\n * const angle = Math.PI / 2; // 90 degrees\n *\n * // Rotate point around origin\n * const rotated = PointCal.rotatePoint(point, angle); // { x: 0, y: 10 }\n *\n * // Rotate around a custom anchor\n * const anchor: Point = { x: 5, y: 5 };\n * const rotatedAroundAnchor = PointCal.transformPointWRTAnchor(point, anchor, angle);\n * ```\n */\n\n/**\n * Represents a 2D or 3D point with optional z-coordinate.\n *\n * @remarks\n * This is a lowercase variant maintained for backward compatibility.\n * Use {@link Point} for new code.\n *\n * @deprecated Use {@link Point} instead for better TypeScript conventions.\n */\nexport type point = {\n /** X-coordinate */\n x: number;\n /** Y-coordinate */\n y: number;\n /** Optional Z-coordinate for 3D operations */\n z?: number;\n}\n\n/**\n * Represents a 2D or 3D point with optional z-coordinate.\n *\n * @remarks\n * When z is undefined, operations treat the point as 2D (z = 0).\n * This type is used throughout the library for all point and vector operations.\n *\n * @example\n * ```typescript\n * // 2D point\n * const p2d: Point = { x: 10, y: 20 };\n *\n * // 3D point\n * const p3d: Point = { x: 10, y: 20, z: 30 };\n * ```\n */\nexport type Point = {\n /** X-coordinate */\n x: number;\n /** Y-coordinate */\n y: number;\n /** Optional Z-coordinate for 3D operations */\n z?: number;\n}\n\n\n/**\n * Utility class for point and vector calculations.\n *\n * @remarks\n * PointCal provides static methods for common 2D and 3D mathematical operations\n * used in canvas applications. All methods handle both 2D and 3D coordinates seamlessly.\n *\n * @example\n * ```typescript\n * import { PointCal, Point } from '@ue-too/math';\n *\n * const v1: Point = { x: 1, y: 2 };\n * const v2: Point = { x: 3, y: 4 };\n *\n * const sum = PointCal.addVector(v1, v2);\n * const dot = PointCal.dotProduct(v1, v2);\n * ```\n */\nexport class PointCal {\n\n /**\n * Adds two vectors together.\n *\n * @param a - First vector\n * @param b - Second vector\n * @returns The sum of vectors a and b\n *\n * @remarks\n * If either vector lacks a z-coordinate, it's treated as 0.\n * The result will include a z-coordinate if either input has one.\n *\n * @example\n * ```typescript\n * const a = { x: 1, y: 2 };\n * const b = { x: 3, y: 4 };\n * const sum = PointCal.addVector(a, b); // { x: 4, y: 6 }\n *\n * // With 3D coordinates\n * const a3d = { x: 1, y: 2, z: 3 };\n * const b3d = { x: 4, y: 5, z: 6 };\n * const sum3d = PointCal.addVector(a3d, b3d); // { x: 5, y: 7, z: 9 }\n * ```\n *\n * @group Vector Arithmetic\n */\n static addVector(a: point, b: point): Point {\n if (a.z == null && b.z == null) return {x: a.x + b.x, y: a.y + b.y};\n if (a.z == null || b.z == null) {\n if (a.z == null) a.z = 0;\n if (b.z == null) b.z = 0;\n }\n return {x: a.x + b.x, y: a.y + b.y, z: a.z + b.z}; \n }\n\n /**\n * Subtracts vector b from vector a.\n *\n * @param a - Vector to subtract from\n * @param b - Vector to subtract\n * @returns The difference (a - b)\n *\n * @remarks\n * If either vector lacks a z-coordinate, it's treated as 0.\n *\n * @example\n * ```typescript\n * const a = { x: 5, y: 7 };\n * const b = { x: 2, y: 3 };\n * const diff = PointCal.subVector(a, b); // { x: 3, y: 4 }\n * ```\n *\n * @group Vector Arithmetic\n */\n static subVector(a: point, b: point): Point {\n if (a.z == null && b.z == null) return {x: a.x - b.x, y: a.y - b.y};\n if (a.z == null || b.z == null) {\n if (a.z == null) a.z = 0;\n if (b.z == null) b.z = 0;\n }\n return {x: a.x - b.x, y: a.y - b.y, z: a.z - b.z};\n }\n\n /**\n * Multiplies a vector by a scalar value.\n *\n * @param a - Vector to multiply\n * @param b - Scalar multiplier\n * @returns The scaled vector\n *\n * @example\n * ```typescript\n * const v = { x: 2, y: 3 };\n * const scaled = PointCal.multiplyVectorByScalar(v, 2.5); // { x: 5, y: 7.5 }\n * ```\n *\n * @group Vector Arithmetic\n */\n static multiplyVectorByScalar(a: point, b: number): Point {\n if (a.z == null) return {x: a.x * b, y: a.y * b};\n return {x: a.x * b, y: a.y * b, z: a.z * b};\n }\n\n /**\n * Divides a vector by a scalar value.\n *\n * @param a - Vector to divide\n * @param b - Scalar divisor\n * @returns The divided vector, or the original vector if b is 0\n *\n * @remarks\n * Division by zero returns the original vector unchanged to prevent NaN values.\n *\n * @example\n * ```typescript\n * const v = { x: 10, y: 20 };\n * const divided = PointCal.divideVectorByScalar(v, 2); // { x: 5, y: 10 }\n * ```\n *\n * @group Vector Arithmetic\n */\n static divideVectorByScalar(a: point, b: number): Point {\n if (b == 0) return {x: a.x, y: a.y};\n if (a.z == null) return {x: a.x / b, y: a.y / b};\n return {x: a.x / b, y: a.y / b, z: a.z / b};\n }\n\n /**\n * Calculates the magnitude (length) of a vector.\n *\n * @param a - Vector to measure\n * @returns The magnitude of the vector\n *\n * @remarks\n * Uses the Euclidean distance formula: √(x² + y² + z²)\n *\n * @example\n * ```typescript\n * const v = { x: 3, y: 4 };\n * const mag = PointCal.magnitude(v); // 5\n *\n * const v3d = { x: 1, y: 2, z: 2 };\n * const mag3d = PointCal.magnitude(v3d); // 3\n * ```\n *\n * @group Vector Operations\n */\n static magnitude(a: point): number {\n if (a.z == null) a.z = 0;\n return Math.sqrt(a.x * a.x + a.y * a.y + a.z * a.z);\n }\n\n /**\n * Converts a vector to its unit vector (normalized to length 1).\n *\n * @param a - Vector to normalize\n * @returns Unit vector in the same direction, or zero vector if magnitude is 0\n *\n * @remarks\n * A unit vector has magnitude 1 and preserves the original direction.\n * Returns {x: 0, y: 0, z: 0} if the input vector has zero magnitude.\n *\n * **Performance note**: This method calls `magnitude()` twice. For better performance\n * when you need both magnitude and unit vector, calculate magnitude once and divide manually.\n *\n * @example\n * ```typescript\n * const v = { x: 3, y: 4 };\n * const unit = PointCal.unitVector(v); // { x: 0.6, y: 0.8 }\n * ```\n *\n * @group Vector Operations\n */\n static unitVector(a: point): Point {\n if (a.z == null) a.z = 0;\n return this.magnitude(a) != 0 ? {x: a.x / this.magnitude(a), y: a.y / this.magnitude(a), z: a.z / this.magnitude(a)} : {x: 0, y: 0, z: 0};\n }\n\n /**\n * Calculates the dot product of two vectors.\n *\n * @param a - First vector\n * @param b - Second vector\n * @returns The dot product (scalar value)\n *\n * @remarks\n * The dot product is: a.x * b.x + a.y * b.y + a.z * b.z\n *\n * **Use cases:**\n * - Determine if vectors are perpendicular (dot = 0)\n * - Calculate angle between vectors: θ = acos(dot / (|a| * |b|))\n * - Project one vector onto another\n *\n * @example\n * ```typescript\n * const a = { x: 1, y: 0 };\n * const b = { x: 0, y: 1 };\n * const dot = PointCal.dotProduct(a, b); // 0 (perpendicular vectors)\n *\n * const c = { x: 2, y: 3 };\n * const d = { x: 4, y: 5 };\n * const dot2 = PointCal.dotProduct(c, d); // 23\n * ```\n *\n * @group Vector Operations\n */\n static dotProduct(a: point, b: point): number {\n if (a.z == null && b.z == null) return a.x * b.x + a.y * b.y;\n if (a.z == null || b.z == null) {\n if (a.z == null) a.z = 0;\n if (b.z == null) b.z = 0;\n }\n return a.x * b.x + a.y * b.y + a.z * b.z;\n }\n\n /**\n * Calculates the cross product of two vectors.\n *\n * @param a - First vector\n * @param b - Second vector\n * @returns The cross product vector perpendicular to both inputs\n *\n * @remarks\n * The cross product is perpendicular to both input vectors, following the right-hand rule.\n * For 2D vectors (z undefined), z is treated as 0.\n *\n * **Properties:**\n * - Result is perpendicular to both input vectors\n * - Magnitude equals area of parallelogram formed by vectors\n * - Direction follows right-hand rule\n *\n * @example\n * ```typescript\n * const a = { x: 1, y: 0, z: 0 };\n * const b = { x: 0, y: 1, z: 0 };\n * const cross = PointCal.crossProduct(a, b); // { x: 0, y: 0, z: 1 }\n * ```\n *\n * @group Vector Operations\n */\n static crossProduct(a: point, b: point): Point {\n if (a.z == null || b.z == null) {\n if (a.z == null) a.z = 0;\n if (b.z == null) b.z = 0;\n }\n return {x: a.y * b.z - a.z * b.y, y: a.z * b.x - a.x * b.z, z: a.x * b.y - a.y * b.x};\n }\n\n /**\n * Calculates the unit vector pointing from point a to point b.\n *\n * @param a - Starting point\n * @param b - Ending point\n * @returns Unit vector in the direction from a to b\n *\n * @remarks\n * Equivalent to calling unitVector(subVector(b, a))\n *\n * @example\n * ```typescript\n * const a = { x: 0, y: 0 };\n * const b = { x: 3, y: 4 };\n * const direction = PointCal.unitVectorFromA2B(a, b); // { x: 0.6, y: 0.8 }\n * ```\n *\n * @group Geometric Calculations\n */\n static unitVectorFromA2B(a: point, b: point): Point {\n return this.unitVector(this.subVector(b, a));\n }\n\n /**\n * Rotates a point around the origin.\n *\n * @param point - Point to rotate\n * @param angle - Rotation angle in radians (counter-clockwise)\n * @returns Rotated point\n *\n * @remarks\n * Rotation is performed around the origin (0, 0).\n * Positive angles rotate counter-clockwise, negative angles rotate clockwise.\n * For rotation around a custom anchor, use {@link transformPointWRTAnchor}.\n *\n * **Performance**: Uses trigonometric functions (sin/cos). For many rotations with\n * the same angle, pre-calculate sin/cos values and apply the transformation manually.\n *\n * @example\n * ```typescript\n * const point = { x: 1, y: 0 };\n * const rotated = PointCal.rotatePoint(point, Math.PI / 2); // { x: 0, y: 1 }\n * ```\n *\n * @group Transformations\n */\n static rotatePoint(point: point, angle: number): Point {\n return {x: point.x * Math.cos(angle) - point.y * Math.sin(angle), y: point.x * Math.sin(angle) + point.y * Math.cos(angle)};\n }\n\n /**\n * Transforms a point's coordinates to a new rotated axis system.\n *\n * @param point - Point in original coordinate system\n * @param angleFromOriginalAxis2DestAxis - Rotation angle from original to destination axis (radians, CCW positive)\n * @returns Point coordinates in the new axis system\n *\n * @remarks\n * This performs an axis rotation transformation, converting coordinates from one\n * reference frame to another rotated by the specified angle.\n *\n * @example\n * ```typescript\n * const point = { x: 10, y: 0 };\n * const angle = Math.PI / 4; // 45 degrees\n * const transformed = PointCal.transform2NewAxis(point, angle);\n * ```\n *\n * @group Transformations\n */\n static transform2NewAxis(point: point, angleFromOriginalAxis2DestAxis: number): Point {\n // angle is the angle from the original axis to the destination axis ccw is positive as always\n return {x: point.x * Math.cos(angleFromOriginalAxis2DestAxis) + point.y * Math.sin(angleFromOriginalAxis2DestAxis), y: -point.x * Math.sin(angleFromOriginalAxis2DestAxis) + point.y * Math.cos(angleFromOriginalAxis2DestAxis)};\n }\n\n /**\n * Calculates the signed angle from vector a to vector b.\n *\n * @param a - First vector (starting direction)\n * @param b - Second vector (ending direction)\n * @returns The signed angle in radians, range: (-π, π]\n *\n * @remarks\n * - Positive angles indicate counter-clockwise rotation from a to b\n * - Negative angles indicate clockwise rotation from a to b\n * - Uses atan2 for proper quadrant handling\n *\n * @example\n * ```typescript\n * const right = { x: 1, y: 0 };\n * const up = { x: 0, y: 1 };\n * const angle = PointCal.angleFromA2B(right, up); // π/2 (90 degrees CCW)\n *\n * const down = { x: 0, y: -1 };\n * const angleDown = PointCal.angleFromA2B(right, down); // -π/2 (90 degrees CW)\n * ```\n *\n * @group Angle Utilities\n */\n static angleFromA2B(a: point, b: point): number {\n return Math.atan2(a.x * b.y - a.y * b.x, a.x * b.x + a.y * b.y);\n }\n\n /**\n * Rotates a point around a custom anchor point.\n *\n * @param point - Point to rotate\n * @param anchor - Anchor point to rotate around\n * @param angle - Rotation angle in radians (counter-clockwise)\n * @returns Rotated point\n *\n * @remarks\n * This is equivalent to:\n * 1. Translate point by -anchor\n * 2. Rotate around origin\n * 3. Translate back by +anchor\n *\n * @example\n * ```typescript\n * const point = { x: 10, y: 5 };\n * const anchor = { x: 5, y: 5 };\n * const angle = Math.PI / 2; // 90 degrees\n * const rotated = PointCal.transformPointWRTAnchor(point, anchor, angle);\n * // Rotates point around anchor (5, 5)\n * ```\n *\n * @group Transformations\n */\n static transformPointWRTAnchor(point: point, anchor: point, angle: number): Point {\n // angle is in radians\n let newPoint = this.rotatePoint(this.subVector(point, anchor), angle);\n return this.addVector(newPoint, anchor);\n }\n\n /**\n * Calculates the Euclidean distance between two points.\n *\n * @param a - First point\n * @param b - Second point\n * @returns The distance between the two points\n *\n * @remarks\n * Equivalent to calculating the magnitude of the vector from a to b.\n *\n * @example\n * ```typescript\n * const a = { x: 0, y: 0 };\n * const b = { x: 3, y: 4 };\n * const distance = PointCal.distanceBetweenPoints(a, b); // 5\n * ```\n *\n * @group Geometric Calculations\n */\n static distanceBetweenPoints(a: point, b: point): number {\n return this.magnitude(this.subVector(a, b));\n }\n\n /**\n * Flips a point's y-coordinate (mirrors across the x-axis).\n *\n * @param point - Point to flip\n * @returns Point with negated y-coordinate\n *\n * @remarks\n * Useful for converting between coordinate systems where the y-axis direction differs.\n * Common when converting between screen coordinates (y-down) and mathematical coordinates (y-up).\n *\n * @example\n * ```typescript\n * const point = { x: 10, y: 20 };\n * const flipped = PointCal.flipYAxis(point); // { x: 10, y: -20 }\n * ```\n *\n * @group Transformations\n */\n static flipYAxis(point: point): Point{\n return {x: point.x, y: -point.y, z: point.z};\n }\n\n /**\n * Performs linear interpolation between two points.\n *\n * @param a - Starting point (t = 0)\n * @param b - Ending point (t = 1)\n * @param t - Interpolation parameter (0 to 1)\n * @returns Interpolated point\n *\n * @remarks\n * - t = 0 returns point a\n * - t = 1 returns point b\n * - t = 0.5 returns the midpoint\n * - Values outside [0, 1] perform extrapolation\n *\n * **Performance**: Suitable for animation loops and real-time interpolation.\n *\n * @example\n * ```typescript\n * const a = { x: 0, y: 0 };\n * const b = { x: 10, y: 20 };\n * const mid = PointCal.linearInterpolation(a, b, 0.5); // { x: 5, y: 10 }\n * const quarter = PointCal.linearInterpolation(a, b, 0.25); // { x: 2.5, y: 5 }\n * ```\n *\n * @group Geometric Calculations\n */\n static linearInterpolation(a: point, b: point, t: number): point{\n if (a.z == null || b.z == null) {\n return {x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t};\n } else {\n return {x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t, z: a.z + (b.z - a.z) * t};\n }\n }\n\n /**\n * Checks if two points are exactly equal.\n *\n * @param a - First point\n * @param b - Second point\n * @returns True if all coordinates are exactly equal\n *\n * @remarks\n * Uses strict equality (===) for comparison.\n * For approximate equality with tolerance, use {@link samePoint} instead.\n * Missing z-coordinates are treated as 0.\n *\n * @example\n * ```typescript\n * const a = { x: 1, y: 2 };\n * const b = { x: 1, y: 2 };\n * PointCal.isEqual(a, b); // true\n *\n * const c = { x: 1.0000001, y: 2 };\n * PointCal.isEqual(a, c); // false (use samePoint for tolerance)\n * ```\n *\n * @group Geometric Calculations\n */\n static isEqual(a: point, b: point): boolean{\n if (a.z == null){\n a.z = 0;\n }\n if (b.z == null){\n b.z = 0;\n }\n return a.x == b.x && a.y == b.y && a.z == b.z;\n }\n\n /**\n * Calculates the intersection point of two line segments.\n *\n * @param startPoint - Start of first line segment\n * @param endPoint - End of first line segment\n * @param startPoint2 - Start of second line segment\n * @param endPoint2 - End of second line segment\n * @returns Object containing intersection status and details\n *\n * @remarks\n * Returns an object with:\n * - `intersects`: Boolean indicating if segments intersect\n * - `intersection`: The intersection point (only if intersects is true)\n * - `offset`: Parameter t where intersection occurs on first segment (0 to 1)\n *\n * The segments must actually cross within their bounds (not just their infinite extensions).\n *\n * **Use cases:**\n * - Collision detection between line segments\n * - Ray casting and visibility checks\n * - Path intersection detection\n *\n * @example\n * ```typescript\n * const line1Start = { x: 0, y: 0 };\n * const line1End = { x: 10, y: 10 };\n * const line2Start = { x: 0, y: 10 };\n * const line2End = { x: 10, y: 0 };\n *\n * const result = PointCal.getLineIntersection(line1Start, line1End, line2Start, line2End);\n * // { intersects: true, intersection: { x: 5, y: 5 }, offset: 0.5 }\n * ```\n *\n * @group Geometric Calculations\n */\n static getLineIntersection(startPoint: Point, endPoint: Point, startPoint2: Point, endPoint2: Point):{\n intersects: boolean,\n intersection?: Point,\n offset?: number\n }{\n const numerator = (endPoint2.x - startPoint2.x) * (startPoint.y - startPoint2.y) - (endPoint2.y - startPoint2.y) * (startPoint.x - startPoint2.x);\n const denominator = (endPoint2.y - startPoint2.y) * (endPoint.x - startPoint.x) - (endPoint2.x - startPoint2.x) * (endPoint.y - startPoint.y);\n \n if (denominator === 0){\n return {intersects: false};\n }\n const t = numerator / denominator;\n if (t >= 0 && t <= 1){\n return {\n intersects: true, \n intersection: PointCal.linearInterpolation(startPoint, endPoint, t),\n offset: t\n }\n } else {\n return {\n intersects: false,\n }\n }\n \n }\n \n}\n\n/**\n * Normalizes an angle to the range [0, 2π).\n *\n * @param angle - Angle in radians (can be any value)\n * @returns Normalized angle between 0 and 2π\n *\n * @remarks\n * This function wraps any angle to the range [0, 2π) by taking the modulo\n * and ensuring the result is positive.\n *\n * @example\n * ```typescript\n * normalizeAngleZero2TwoPI(Math.PI * 3); // π (180 degrees)\n * normalizeAngleZero2TwoPI(-Math.PI / 2); // 3π/2 (270 degrees)\n * normalizeAngleZero2TwoPI(0); // 0\n * ```\n *\n * @category Angle\n */\nexport function normalizeAngleZero2TwoPI(angle: number){\n // reduce the angle \n angle = angle % (Math.PI * 2);\n\n // force it to be the positive remainder, so that 0 <= angle < 2 * Math.PI \n angle = (angle + Math.PI * 2) % (Math.PI * 2); \n return angle;\n}\n\n/**\n * Calculates the smallest angular difference between two angles.\n *\n * @param from - Starting angle in radians\n * @param to - Ending angle in radians\n * @returns The smallest angle span from 'from' to 'to', in range (-π, π]\n *\n * @remarks\n * This function accounts for wrapping around 2π and always returns the shorter path.\n * Positive result means counter-clockwise rotation, negative means clockwise.\n *\n * @example\n * ```typescript\n * // From 0° to 90°\n * angleSpan(0, Math.PI / 2); // π/2 (90 degrees CCW)\n *\n * // From 350° to 10° (shorter to go CCW through 0°)\n * angleSpan(350 * Math.PI / 180, 10 * Math.PI / 180); // ≈ 20 degrees\n *\n * // From 10° to 350° (shorter to go CW through 0°)\n * angleSpan(10 * Math.PI / 180, 350 * Math.PI / 180); // ≈ -20 degrees\n * ```\n *\n * @category Angle\n */\nexport function angleSpan(from: number, to: number): number{\n // in radians\n from = normalizeAngleZero2TwoPI(from);\n to = normalizeAngleZero2TwoPI(to);\n let angleDiff = to - from;\n \n if(angleDiff > Math.PI){\n angleDiff = - (Math.PI * 2 - angleDiff);\n }\n\n if(angleDiff < -Math.PI){\n angleDiff += (Math.PI * 2);\n }\n return angleDiff;\n}\n\n/**\n * Checks if two numbers are approximately equal within a tolerance.\n *\n * @param a - First number\n * @param b - Second number\n * @param precision - Optional tolerance (defaults to 0.000001)\n * @returns True if the absolute difference is within the precision threshold\n *\n * @remarks\n * Useful for floating-point comparisons where exact equality is unreliable.\n *\n * @example\n * ```typescript\n * approximatelyTheSame(1.0, 1.0000001); // true (within default epsilon)\n * approximatelyTheSame(1.0, 1.1); // false\n * approximatelyTheSame(1.0, 1.01, 0.02); // true (within custom precision)\n * ```\n *\n * @category Comparison\n */\nexport function approximatelyTheSame(a: number, b: number, precision?: number): boolean {\n const epsilon = 0.000001\n return Math.abs(a - b) <= (precision || epsilon);\n}\n\n/**\n * Checks if two vectors point in the same direction.\n *\n * @param a - First vector\n * @param b - Second vector\n * @param precision - Tolerance for comparison (defaults to 0.001)\n * @returns True if vectors have the same direction (after normalization)\n *\n * @remarks\n * Normalizes both vectors to unit vectors and compares them.\n * Magnitude does not matter, only direction.\n *\n * @example\n * ```typescript\n * const a = { x: 1, y: 0 };\n * const b = { x: 10, y: 0 }; // Same direction, different magnitude\n * sameDirection(a, b); // true\n *\n * const c = { x: 1, y: 1 };\n * sameDirection(a, c); // false (different direction)\n * ```\n *\n * @category Comparison\n */\nexport function sameDirection(a: Point, b: Point, precision: number = 0.001): boolean{\n const aNormalized = PointCal.unitVector(a);\n const bNormalized = PointCal.unitVector(b);\n return samePoint(aNormalized, bNormalized, precision);\n}\n\n/**\n * Checks if a direction vector is aligned with a tangent vector.\n *\n * @param direction - Direction vector to check\n * @param tangent - Tangent vector reference\n * @returns True if direction aligns with tangent (within 90 degrees)\n *\n * @remarks\n * Returns true if the direction is within 90 degrees of either the tangent\n * or its reverse. Useful for determining if movement is along a path.\n *\n * @example\n * ```typescript\n * const direction = { x: 1, y: 0 };\n * const tangent = { x: 1, y: 0.1 }; // Slightly rotated\n * directionAlignedToTangent(direction, tangent); // true\n *\n * const perpendicular = { x: 0, y: 1 };\n * directionAlignedToTangent(perpendicular, tangent); // false\n * ```\n *\n * @category Comparison\n */\nexport function directionAlignedToTangent(direction: Point, tangent: Point): boolean {\n const directionNormalized = PointCal.unitVector(direction);\n const tangentNormalized = PointCal.unitVector(tangent);\n const reversedTangent = {x: -tangent.x, y: -tangent.y, z: tangent.z};\n const angle = PointCal.angleFromA2B(directionNormalized, tangentNormalized);\n const angle2 = PointCal.angleFromA2B(directionNormalized, reversedTangent);\n return (angle < Math.PI / 2 && angle > -Math.PI / 2) && (angle2 > Math.PI / 2 || angle2 < -Math.PI / 2);\n}\n\n/**\n * Checks if two points are approximately at the same location.\n *\n * @param a - First point\n * @param b - Second point\n * @param precision - Optional tolerance for coordinate comparison\n * @returns True if both x and y coordinates are within precision\n *\n * @remarks\n * Uses {@link approximatelyTheSame} for coordinate comparison.\n * For exact equality, use {@link PointCal.isEqual} instead.\n *\n * @example\n * ```typescript\n * const a = { x: 1.0, y: 2.0 };\n * const b = { x: 1.0000001, y: 2.0000001 };\n * samePoint(a, b); // true (within default precision)\n *\n * const c = { x: 1.1, y: 2.0 };\n * samePoint(a, c); // false\n * ```\n *\n * @category Comparison\n */\nexport function samePoint(a: Point, b: Point, precision?: number): boolean {\n if(approximatelyTheSame(a.x, b.x, precision) && approximatelyTheSame(a.y, b.y, precision)){\n return true;\n }\n return false;\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "E7FBAB931781982464756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|