@khanacademy/kmath 0.0.8 → 0.1.1
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/.babelrc.js +1 -1
- package/.eslintrc.js +1 -0
- package/CHANGELOG.md +12 -0
- package/dist/es/index.js +131 -134
- package/dist/es/index.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.js +84 -85
- package/dist/index.js.flow +11 -2
- package/dist/index.js.map +1 -1
- package/dist/line.d.ts +10 -0
- package/dist/line.js.flow +16 -0
- package/dist/logo.d.ts +2 -0
- package/dist/logo.js.flow +8 -0
- package/dist/number.d.ts +29 -0
- package/dist/number.js.flow +44 -0
- package/dist/point.d.ts +34 -0
- package/dist/point.js.flow +52 -0
- package/dist/ray.d.ts +9 -0
- package/dist/ray.js.flow +13 -0
- package/dist/vector.d.ts +38 -0
- package/dist/vector.js.flow +74 -0
- package/package.json +3 -3
- package/src/__tests__/{line.test.js → line.test.ts} +1 -3
- package/src/__tests__/{number.test.js → number.test.ts} +4 -4
- package/src/__tests__/{point.test.js → point.test.ts} +1 -3
- package/src/__tests__/{vector.test.js → vector.test.ts} +1 -3
- package/src/index.ts +5 -0
- package/src/{line.js → line.ts} +3 -4
- package/src/{logo.js → logo.ts} +3 -7
- package/src/{number.js → number.ts} +4 -4
- package/src/{point.js → point.ts} +4 -5
- package/src/{ray.js → ray.ts} +2 -3
- package/src/{vector.js → vector.ts} +35 -38
- package/tsconfig.json +9 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/src/index.js +0 -7
package/.babelrc.js
CHANGED
package/.eslintrc.js
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @khanacademy/kmath
|
|
2
2
|
|
|
3
|
+
## 0.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 1f062e98: Bump all package versions since the build settings have been updated
|
|
8
|
+
|
|
9
|
+
## 0.1.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 53fd3768: Migrate source code to TypeScript
|
|
14
|
+
|
|
3
15
|
## 0.0.8
|
|
4
16
|
|
|
5
17
|
### Patch Changes
|
package/dist/es/index.js
CHANGED
|
@@ -4,9 +4,10 @@ import _ from 'underscore';
|
|
|
4
4
|
* Number Utils
|
|
5
5
|
* A number is a js-number, e.g. 5.12
|
|
6
6
|
*/
|
|
7
|
-
|
|
7
|
+
const DEFAULT_TOLERANCE = 1e-9;
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
// TODO: Should this just be Number.Epsilon
|
|
10
|
+
const EPSILON = Math.pow(2, -42);
|
|
10
11
|
function is$2(x) {
|
|
11
12
|
return _.isNumber(x) && !_.isNaN(x);
|
|
12
13
|
}
|
|
@@ -15,34 +16,31 @@ function equal$4(x, y, tolerance) {
|
|
|
15
16
|
// with vectors of different lengths that are _.zip'd together
|
|
16
17
|
if (x == null || y == null) {
|
|
17
18
|
return x === y;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
}
|
|
20
|
+
// We check === here so that +/-Infinity comparisons work correctly
|
|
21
21
|
if (x === y) {
|
|
22
22
|
return true;
|
|
23
23
|
}
|
|
24
|
-
|
|
25
24
|
if (tolerance == null) {
|
|
26
25
|
tolerance = DEFAULT_TOLERANCE;
|
|
27
26
|
}
|
|
28
|
-
|
|
29
27
|
return Math.abs(x - y) < tolerance;
|
|
30
28
|
}
|
|
31
|
-
function sign(x, tolerance)
|
|
32
|
-
/* Should be: 0 | 1 | -1 */
|
|
33
|
-
{
|
|
29
|
+
function sign(x, tolerance) /* Should be: 0 | 1 | -1 */{
|
|
34
30
|
return equal$4(x, 0, tolerance) ? 0 : Math.abs(x) / x;
|
|
35
31
|
}
|
|
36
32
|
function isInteger(num, tolerance) {
|
|
37
33
|
return equal$4(Math.round(num), num, tolerance);
|
|
38
|
-
}
|
|
34
|
+
}
|
|
39
35
|
|
|
36
|
+
// Round a number to a certain number of decimal places
|
|
40
37
|
function round$2(num, precision) {
|
|
41
|
-
|
|
38
|
+
const factor = Math.pow(10, precision);
|
|
42
39
|
return Math.round(num * factor) / factor;
|
|
43
|
-
}
|
|
44
|
-
// i.e. roundTo(83, 5) -> 85
|
|
40
|
+
}
|
|
45
41
|
|
|
42
|
+
// Round num to the nearest multiple of increment
|
|
43
|
+
// i.e. roundTo(83, 5) -> 85
|
|
46
44
|
function roundTo$2(num, increment) {
|
|
47
45
|
return Math.round(num / increment) * increment;
|
|
48
46
|
}
|
|
@@ -52,6 +50,7 @@ function floorTo$2(num, increment) {
|
|
|
52
50
|
function ceilTo$2(num, increment) {
|
|
53
51
|
return Math.ceil(num / increment) * increment;
|
|
54
52
|
}
|
|
53
|
+
|
|
55
54
|
/**
|
|
56
55
|
* toFraction
|
|
57
56
|
*
|
|
@@ -66,30 +65,27 @@ function ceilTo$2(num, increment) {
|
|
|
66
65
|
* toFraction(0.66, 0.01) => [2/3]
|
|
67
66
|
* toFraction(283 + 1/3) => [850, 3]
|
|
68
67
|
*/
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
var maxDenominator = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1000;
|
|
68
|
+
function toFraction(decimal,
|
|
69
|
+
// can't be 0
|
|
70
|
+
tolerance = EPSILON, maxDenominator = 1000) {
|
|
73
71
|
// Initialize everything to compute successive terms of
|
|
74
72
|
// continued-fraction approximations via recurrence relation
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
73
|
+
let n = [1, 0];
|
|
74
|
+
let d = [0, 1];
|
|
75
|
+
let a = Math.floor(decimal);
|
|
76
|
+
let rem = decimal - a;
|
|
80
77
|
while (d[0] <= maxDenominator) {
|
|
81
78
|
if (equal$4(n[0] / d[0], decimal, tolerance)) {
|
|
82
79
|
return [n[0], d[0]];
|
|
83
80
|
}
|
|
84
|
-
|
|
85
81
|
n = [a * n[0] + n[1], n[0]];
|
|
86
82
|
d = [a * d[0] + d[1], d[0]];
|
|
87
83
|
a = Math.floor(1 / rem);
|
|
88
84
|
rem = 1 / rem - a;
|
|
89
|
-
}
|
|
90
|
-
// so return an irrational "fraction"
|
|
91
|
-
|
|
85
|
+
}
|
|
92
86
|
|
|
87
|
+
// We failed to find a nice rational representation,
|
|
88
|
+
// so return an irrational "fraction"
|
|
93
89
|
return [decimal, 1];
|
|
94
90
|
}
|
|
95
91
|
|
|
@@ -112,14 +108,13 @@ var number = /*#__PURE__*/Object.freeze({
|
|
|
112
108
|
* Vector Utils
|
|
113
109
|
* A vector is an array of numbers e.g. [0, 3, 4].
|
|
114
110
|
*/
|
|
115
|
-
|
|
116
111
|
function arraySum(array) {
|
|
117
112
|
return array.reduce((memo, arg) => memo + arg, 0);
|
|
118
113
|
}
|
|
119
|
-
|
|
120
114
|
function arrayProduct(array) {
|
|
121
115
|
return array.reduce((memo, arg) => memo * arg, 1);
|
|
122
116
|
}
|
|
117
|
+
|
|
123
118
|
/**
|
|
124
119
|
* Checks if the given vector contains only numbers and, optionally, is of the
|
|
125
120
|
* right dimension (length).
|
|
@@ -128,59 +123,55 @@ function arrayProduct(array) {
|
|
|
128
123
|
* is([1, "Hello", 3]) -> false
|
|
129
124
|
* is([1, 2, 3], 1) -> false
|
|
130
125
|
*/
|
|
131
|
-
|
|
132
|
-
|
|
133
126
|
function is$1(vec, dimension) {
|
|
134
127
|
if (!_.isArray(vec)) {
|
|
135
128
|
return false;
|
|
136
129
|
}
|
|
137
|
-
|
|
138
130
|
if (dimension !== undefined && vec.length !== dimension) {
|
|
139
131
|
return false;
|
|
140
132
|
}
|
|
141
|
-
|
|
142
133
|
return vec.every(is$2);
|
|
143
|
-
}
|
|
134
|
+
}
|
|
144
135
|
|
|
136
|
+
// Normalize to a unit vector
|
|
145
137
|
function normalize(v) {
|
|
146
138
|
return scale(v, 1 / length(v));
|
|
147
|
-
}
|
|
139
|
+
}
|
|
148
140
|
|
|
141
|
+
// Length/magnitude of a vector
|
|
149
142
|
function length(v) {
|
|
150
143
|
return Math.sqrt(dot(v, v));
|
|
151
|
-
}
|
|
152
|
-
|
|
144
|
+
}
|
|
145
|
+
// Dot product of two vectors
|
|
153
146
|
function dot(a, b) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
var multiplied = zipped.map(arrayProduct);
|
|
147
|
+
const zipped = _.zip(a, b);
|
|
148
|
+
const multiplied = zipped.map(arrayProduct);
|
|
158
149
|
return arraySum(multiplied);
|
|
159
150
|
}
|
|
151
|
+
|
|
160
152
|
/* vector-add multiple [x, y] coords/vectors
|
|
161
153
|
*
|
|
162
154
|
* add([1, 2], [3, 4]) -> [4, 6]
|
|
163
155
|
*/
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
//
|
|
167
|
-
var zipped = _.zip(...arguments);
|
|
168
|
-
|
|
156
|
+
function add(...vecs) {
|
|
157
|
+
const zipped = _.zip(...vecs);
|
|
158
|
+
// @ts-expect-error [FEI-5003] - TS2322 - Type 'number[]' is not assignable to type 'V'.
|
|
169
159
|
return zipped.map(arraySum);
|
|
170
160
|
}
|
|
171
161
|
function subtract(v1, v2) {
|
|
172
|
-
//
|
|
162
|
+
// @ts-expect-error [FEI-5003] - TS2322 - Type 'number[]' is not assignable to type 'V'.
|
|
173
163
|
return _.zip(v1, v2).map(dim => dim[0] - dim[1]);
|
|
174
164
|
}
|
|
175
165
|
function negate(v) {
|
|
176
|
-
//
|
|
166
|
+
// @ts-expect-error [FEI-5003] - TS2322 - Type 'number[]' is not assignable to type 'V'.
|
|
177
167
|
return v.map(x => {
|
|
178
168
|
return -x;
|
|
179
169
|
});
|
|
180
|
-
}
|
|
170
|
+
}
|
|
181
171
|
|
|
172
|
+
// Scale a vector
|
|
182
173
|
function scale(v1, scalar) {
|
|
183
|
-
//
|
|
174
|
+
// @ts-expect-error [FEI-5003] - TS2322 - Type 'number[]' is not assignable to type 'V'.
|
|
184
175
|
return v1.map(x => {
|
|
185
176
|
return x * scalar;
|
|
186
177
|
});
|
|
@@ -190,7 +181,6 @@ function equal$3(v1, v2, tolerance) {
|
|
|
190
181
|
// the length of the longest vector. knumber.equal then
|
|
191
182
|
// returns false for any number compared to the undefined
|
|
192
183
|
// passed in if one of the vectors is shorter.
|
|
193
|
-
// $FlowFixMe[incompatible-call] underscore doesn't like $ReadOnlyArray
|
|
194
184
|
return _.zip(v1, v2).every(pair => equal$4(pair[0], pair[1], tolerance));
|
|
195
185
|
}
|
|
196
186
|
function codirectional(v1, v2, tolerance) {
|
|
@@ -200,101 +190,106 @@ function codirectional(v1, v2, tolerance) {
|
|
|
200
190
|
if (equal$4(length(v1), 0, tolerance) || equal$4(length(v2), 0, tolerance)) {
|
|
201
191
|
return true;
|
|
202
192
|
}
|
|
203
|
-
|
|
204
193
|
v1 = normalize(v1);
|
|
205
194
|
v2 = normalize(v2);
|
|
206
195
|
return equal$3(v1, v2, tolerance);
|
|
207
196
|
}
|
|
208
197
|
function collinear(v1, v2, tolerance) {
|
|
209
198
|
return codirectional(v1, v2, tolerance) || codirectional(v1, negate(v2), tolerance);
|
|
210
|
-
}
|
|
211
|
-
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// TODO(jeremy) These coordinate conversion functions really only handle 2D points (ie. [number, number])
|
|
212
202
|
|
|
203
|
+
// Convert a cartesian coordinate into a radian polar coordinate
|
|
213
204
|
function polarRadFromCart$1(v) {
|
|
214
|
-
|
|
215
|
-
|
|
205
|
+
const radius = length(v);
|
|
206
|
+
let theta = Math.atan2(v[1], v[0]);
|
|
216
207
|
|
|
208
|
+
// Convert angle range from [-pi, pi] to [0, 2pi]
|
|
217
209
|
if (theta < 0) {
|
|
218
210
|
theta += 2 * Math.PI;
|
|
219
211
|
}
|
|
220
|
-
|
|
221
212
|
return [radius, theta];
|
|
222
|
-
}
|
|
213
|
+
}
|
|
223
214
|
|
|
224
|
-
|
|
225
|
-
/* TODO: convert to tuple/Point */
|
|
226
|
-
|
|
227
|
-
var polar = polarRadFromCart$1(v);
|
|
215
|
+
// Converts a cartesian coordinate into a degree polar coordinate
|
|
216
|
+
function polarDegFromCart$1(v) /* TODO: convert to tuple/Point */{
|
|
217
|
+
const polar = polarRadFromCart$1(v);
|
|
228
218
|
return [polar[0], polar[1] * 180 / Math.PI];
|
|
229
219
|
}
|
|
220
|
+
|
|
230
221
|
/* Convert a polar coordinate into a cartesian coordinate
|
|
231
222
|
*
|
|
232
223
|
* Examples:
|
|
233
224
|
* cartFromPolarRad(5, Math.PI)
|
|
234
225
|
*/
|
|
235
|
-
|
|
236
|
-
function cartFromPolarRad$1(radius)
|
|
237
|
-
/* TODO: convert to tuple/Point */
|
|
238
|
-
{
|
|
239
|
-
var theta = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
226
|
+
function cartFromPolarRad$1(radius, theta = 0) /* TODO: convert to tuple/Point */{
|
|
240
227
|
return [radius * Math.cos(theta), radius * Math.sin(theta)];
|
|
241
228
|
}
|
|
229
|
+
|
|
242
230
|
/* Convert a polar coordinate into a cartesian coordinate
|
|
243
231
|
*
|
|
244
232
|
* Examples:
|
|
245
233
|
* cartFromPolarDeg(5, 30)
|
|
246
234
|
*/
|
|
247
|
-
|
|
248
|
-
function cartFromPolarDeg$1(radius) {
|
|
249
|
-
var theta = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
|
|
235
|
+
function cartFromPolarDeg$1(radius, theta = 0) {
|
|
250
236
|
return cartFromPolarRad$1(radius, theta * Math.PI / 180);
|
|
251
|
-
}
|
|
237
|
+
}
|
|
252
238
|
|
|
239
|
+
// Rotate vector
|
|
253
240
|
function rotateRad$1(v, theta) {
|
|
254
|
-
|
|
255
|
-
|
|
241
|
+
const polar = polarRadFromCart$1(v);
|
|
242
|
+
const angle = polar[1] + theta;
|
|
256
243
|
return cartFromPolarRad$1(polar[0], angle);
|
|
257
244
|
}
|
|
258
245
|
function rotateDeg$1(v, theta) {
|
|
259
|
-
|
|
260
|
-
|
|
246
|
+
const polar = polarDegFromCart$1(v);
|
|
247
|
+
const angle = polar[1] + theta;
|
|
261
248
|
return cartFromPolarDeg$1(polar[0], angle);
|
|
262
|
-
}
|
|
249
|
+
}
|
|
263
250
|
|
|
251
|
+
// Angle between two vectors
|
|
264
252
|
function angleRad(v1, v2) {
|
|
265
253
|
return Math.acos(dot(v1, v2) / (length(v1) * length(v2)));
|
|
266
254
|
}
|
|
267
255
|
function angleDeg(v1, v2) {
|
|
268
256
|
return angleRad(v1, v2) * 180 / Math.PI;
|
|
269
|
-
}
|
|
257
|
+
}
|
|
270
258
|
|
|
259
|
+
// Vector projection of v1 onto v2
|
|
271
260
|
function projection(v1, v2) {
|
|
272
|
-
|
|
261
|
+
const scalar = dot(v1, v2) / dot(v2, v2);
|
|
273
262
|
return scale(v2, scalar);
|
|
274
|
-
}
|
|
263
|
+
}
|
|
275
264
|
|
|
265
|
+
// Round each number to a certain number of decimal places
|
|
276
266
|
function round$1(vec, precision) {
|
|
277
|
-
//
|
|
278
|
-
return vec.map((elem, i) =>
|
|
267
|
+
// @ts-expect-error [FEI-5003] - TS2322 - Type 'number[]' is not assignable to type 'V'.
|
|
268
|
+
return vec.map((elem, i) =>
|
|
269
|
+
// $FlowFixMe[prop-missing]
|
|
279
270
|
// $FlowFixMe[incompatible-call]
|
|
280
271
|
round$2(elem, precision[i] || precision));
|
|
281
|
-
}
|
|
272
|
+
}
|
|
282
273
|
|
|
274
|
+
// Round each number to the nearest increment
|
|
283
275
|
function roundTo$1(vec, increment) {
|
|
284
|
-
//
|
|
285
|
-
return vec.map((elem, i) =>
|
|
276
|
+
// @ts-expect-error [FEI-5003] - TS2322 - Type 'number[]' is not assignable to type 'V'.
|
|
277
|
+
return vec.map((elem, i) =>
|
|
278
|
+
// $FlowFixMe[prop-missing]
|
|
286
279
|
// $FlowFixMe[incompatible-call]
|
|
287
280
|
roundTo$2(elem, increment[i] || increment));
|
|
288
281
|
}
|
|
289
282
|
function floorTo$1(vec, increment) {
|
|
290
|
-
//
|
|
291
|
-
return vec.map((elem, i) =>
|
|
283
|
+
// @ts-expect-error [FEI-5003] - TS2322 - Type 'number[]' is not assignable to type 'V'.
|
|
284
|
+
return vec.map((elem, i) =>
|
|
285
|
+
// $FlowFixMe[prop-missing]
|
|
292
286
|
// $FlowFixMe[incompatible-call]
|
|
293
287
|
floorTo$2(elem, increment[i] || increment));
|
|
294
288
|
}
|
|
295
289
|
function ceilTo$1(vec, increment) {
|
|
296
|
-
//
|
|
297
|
-
return vec.map((elem, i) =>
|
|
290
|
+
// @ts-expect-error [FEI-5003] - TS2322 - Type 'number[]' is not assignable to type 'V'.
|
|
291
|
+
return vec.map((elem, i) =>
|
|
292
|
+
// $FlowFixMe[prop-missing]
|
|
298
293
|
// $FlowFixMe[incompatible-call]
|
|
299
294
|
ceilTo$2(elem, increment[i] || increment));
|
|
300
295
|
}
|
|
@@ -332,6 +327,8 @@ var vector = /*#__PURE__*/Object.freeze({
|
|
|
332
327
|
* A point is an array of two numbers e.g. [0, 0].
|
|
333
328
|
*/
|
|
334
329
|
|
|
330
|
+
// A point, in 2D, 3D, or nD space.
|
|
331
|
+
|
|
335
332
|
// Rotate point (around origin unless a center is specified)
|
|
336
333
|
function rotateRad(point, theta, center) {
|
|
337
334
|
if (center === undefined) {
|
|
@@ -346,27 +343,31 @@ function rotateDeg(point, theta, center) {
|
|
|
346
343
|
} else {
|
|
347
344
|
return add(center, rotateDeg$1(subtract(point, center), theta));
|
|
348
345
|
}
|
|
349
|
-
}
|
|
346
|
+
}
|
|
350
347
|
|
|
348
|
+
// Distance between two points
|
|
351
349
|
function distanceToPoint$1(point1, point2) {
|
|
352
350
|
return length(subtract(point1, point2));
|
|
353
|
-
}
|
|
351
|
+
}
|
|
354
352
|
|
|
353
|
+
// Distance between point and line
|
|
355
354
|
function distanceToLine(point, line) {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
355
|
+
const lv = subtract(line[1], line[0]);
|
|
356
|
+
const pv = subtract(point, line[0]);
|
|
357
|
+
const projectedPv = projection(pv, lv);
|
|
358
|
+
const distancePv = subtract(projectedPv, pv);
|
|
360
359
|
return length(distancePv);
|
|
361
|
-
}
|
|
360
|
+
}
|
|
362
361
|
|
|
362
|
+
// Reflect point over line
|
|
363
363
|
function reflectOverLine(point, line) {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
364
|
+
const lv = subtract(line[1], line[0]);
|
|
365
|
+
const pv = subtract(point, line[0]);
|
|
366
|
+
const projectedPv = projection(pv, lv);
|
|
367
|
+
const reflectedPv = subtract(scale(projectedPv, 2), pv);
|
|
368
368
|
return add(line[0], reflectedPv);
|
|
369
369
|
}
|
|
370
|
+
|
|
370
371
|
/**
|
|
371
372
|
* Compares two points, returning -1, 0, or 1, for use with
|
|
372
373
|
* Array.prototype.sort
|
|
@@ -376,39 +377,38 @@ function reflectOverLine(point, line) {
|
|
|
376
377
|
* is 0. In some cases very close points that compare within a
|
|
377
378
|
* few equalityTolerances could appear in the wrong order.
|
|
378
379
|
*/
|
|
379
|
-
|
|
380
|
-
function compare(point1, point2, equalityTolerance)
|
|
381
|
-
/* TODO: convert to -1 | 0 | 1 type */
|
|
382
|
-
{
|
|
380
|
+
function compare(point1, point2, equalityTolerance) /* TODO: convert to -1 | 0 | 1 type */{
|
|
383
381
|
if (point1.length !== point2.length) {
|
|
384
382
|
return point1.length - point2.length;
|
|
385
383
|
}
|
|
386
|
-
|
|
387
|
-
for (var i = 0; i < point1.length; i++) {
|
|
384
|
+
for (let i = 0; i < point1.length; i++) {
|
|
388
385
|
if (!equal$4(point1[i], point2[i], equalityTolerance)) {
|
|
389
386
|
return point1[i] - point2[i];
|
|
390
387
|
}
|
|
391
388
|
}
|
|
392
|
-
|
|
393
389
|
return 0;
|
|
394
|
-
}
|
|
390
|
+
}
|
|
395
391
|
|
|
396
|
-
|
|
392
|
+
// Check if a value is a point
|
|
393
|
+
const is = is$1;
|
|
397
394
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
395
|
+
// Add and subtract vector(s)
|
|
396
|
+
const addVector = add;
|
|
397
|
+
const addVectors = add;
|
|
398
|
+
const subtractVector = subtract;
|
|
399
|
+
const equal$2 = equal$3;
|
|
402
400
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
401
|
+
// Convert from cartesian to polar and back
|
|
402
|
+
const polarRadFromCart = polarRadFromCart$1;
|
|
403
|
+
const polarDegFromCart = polarDegFromCart$1;
|
|
404
|
+
const cartFromPolarRad = cartFromPolarRad$1;
|
|
405
|
+
const cartFromPolarDeg = cartFromPolarDeg$1;
|
|
407
406
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
407
|
+
// Rounding
|
|
408
|
+
const round = round$1;
|
|
409
|
+
const roundTo = roundTo$1;
|
|
410
|
+
const floorTo = floorTo$1;
|
|
411
|
+
const ceilTo = ceilTo$1;
|
|
412
412
|
|
|
413
413
|
var point = /*#__PURE__*/Object.freeze({
|
|
414
414
|
__proto__: null,
|
|
@@ -450,21 +450,18 @@ function equal$1(line1, line2, tolerance) {
|
|
|
450
450
|
// TODO: A nicer implementation might just check collinearity of
|
|
451
451
|
// vectors using underscore magick
|
|
452
452
|
// Compare the directions of the lines
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
453
|
+
const v1 = subtract(line1[1], line1[0]);
|
|
454
|
+
const v2 = subtract(line2[1], line2[0]);
|
|
456
455
|
if (!collinear(v1, v2, tolerance)) {
|
|
457
456
|
return false;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
|
|
457
|
+
}
|
|
458
|
+
// If the start point is the same for the two lines, then they are the same
|
|
461
459
|
if (equal$2(line1[0], line2[0])) {
|
|
462
460
|
return true;
|
|
463
|
-
}
|
|
461
|
+
}
|
|
462
|
+
// Make sure that the direction to get from line1 to
|
|
464
463
|
// line2 is the same as the direction of the lines
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
var line1ToLine2Vector = subtract(line2[0], line1[0]);
|
|
464
|
+
const line1ToLine2Vector = subtract(line2[0], line1[0]);
|
|
468
465
|
return collinear(v1, line1ToLine2Vector, tolerance);
|
|
469
466
|
}
|
|
470
467
|
|
|
@@ -484,10 +481,10 @@ var line = /*#__PURE__*/Object.freeze({
|
|
|
484
481
|
*/
|
|
485
482
|
function equal(ray1, ray2, tolerance) {
|
|
486
483
|
// Compare the directions of the rays
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
484
|
+
const v1 = subtract(ray1[1], ray1[0]);
|
|
485
|
+
const v2 = subtract(ray2[1], ray2[0]);
|
|
486
|
+
const sameOrigin = equal$2(ray1[0], ray2[0]);
|
|
487
|
+
const codirectional$1 = codirectional(v1, v2, tolerance);
|
|
491
488
|
return sameOrigin && codirectional$1;
|
|
492
489
|
}
|
|
493
490
|
|