@khanacademy/kmath 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.babelrc.js +8 -0
- package/README.md +465 -0
- package/dist/es/index.js +2 -0
- package/dist/es/index.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.flow +2 -0
- package/dist/index.js.map +1 -0
- package/khanacademy-kmath-v0.0.3.tgz +0 -0
- package/logo.svg +1 -0
- package/package.json +24 -0
- package/src/__tests__/line.test.js +119 -0
- package/src/__tests__/number.test.js +119 -0
- package/src/__tests__/point.test.js +50 -0
- package/src/__tests__/vector.test.js +113 -0
- package/src/index.js +7 -0
- package/src/line.js +46 -0
- package/src/logo.js +41 -0
- package/src/number.js +104 -0
- package/src/point.js +108 -0
- package/src/ray.js +25 -0
- package/src/vector.js +267 -0
package/.babelrc.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HACK(somewhatabstract): Due to https://github.com/facebook/jest/issues/11741,
|
|
3
|
+
* we need to have this file, or updating inline snapshots can fail rather
|
|
4
|
+
* cryptically.
|
|
5
|
+
*
|
|
6
|
+
* We should remove this when jest is fixed.
|
|
7
|
+
*/
|
|
8
|
+
module.exports = require("../../config/build/babel.config");
|
package/README.md
ADDED
|
@@ -0,0 +1,465 @@
|
|
|
1
|
+
# kmath
|
|
2
|
+
|
|
3
|
+
Javascript Numeric Math Utilities
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
kmath is a collection of Javascript utility functions for performing
|
|
8
|
+
numeric (rather than algebraic) math that isn't built into Javascript,
|
|
9
|
+
especially geometric calculations.
|
|
10
|
+
|
|
11
|
+
For example, some computations are easy to express using vectors, but
|
|
12
|
+
difficult to express in terms of raw real number variables. kmath lets
|
|
13
|
+
you write vector-, point-, line-, or ray-based math naturally, and
|
|
14
|
+
also has some real number utility methods that might be useful if
|
|
15
|
+
you're writing a math-heavy Javascript application.
|
|
16
|
+
|
|
17
|
+
kmath emphasizes simplicity and interoperability in the interfaces
|
|
18
|
+
provided. All kmath interfaces use standard Javascript types, usually
|
|
19
|
+
numbers, arrays of numbers, or arrays of arrays of numbers. This means
|
|
20
|
+
interoping with other systems (other libraries, or sending kmath types
|
|
21
|
+
over json) is easy, but kmath doesn't have it's own object-oriented
|
|
22
|
+
types, which may be inconvenient (for example, in debugging, you'll
|
|
23
|
+
just see Arrays rather than, for example, Vectors).
|
|
24
|
+
|
|
25
|
+
kmath also focuses on being a high quality library of a few functions,
|
|
26
|
+
rather than a large library of many functions which are less unified.
|
|
27
|
+
|
|
28
|
+
kmath emphasizes simplicity in design over performance, when those two
|
|
29
|
+
are at odds. If you are writing code in an inner loop in an allocation-
|
|
30
|
+
sensitive environment, kmath might not be for you. Each method is
|
|
31
|
+
pure and allocates a new array for the return value.
|
|
32
|
+
|
|
33
|
+
## Getting started
|
|
34
|
+
|
|
35
|
+
After cloning or downloading kmath, you can install it by running
|
|
36
|
+
`npm install` or `make install`.
|
|
37
|
+
|
|
38
|
+
To play around with the available interfaces, you can load kmath
|
|
39
|
+
into a Node repl:
|
|
40
|
+
|
|
41
|
+
$ node
|
|
42
|
+
> var kmath = require("@khanacademy/kmath");
|
|
43
|
+
> kmath.vector.add([1, 2], [3, 4])
|
|
44
|
+
[4, 6]
|
|
45
|
+
|
|
46
|
+
## Usage overview
|
|
47
|
+
|
|
48
|
+
kmath has 5 basic types:
|
|
49
|
+
|
|
50
|
+
- number
|
|
51
|
+
- vector
|
|
52
|
+
- point
|
|
53
|
+
- ray
|
|
54
|
+
- line
|
|
55
|
+
|
|
56
|
+
Each has its own representation:
|
|
57
|
+
|
|
58
|
+
- number: a js number (i.e. `5`)
|
|
59
|
+
- vector: a js array of numbers (i.e. `[5, 6]`)
|
|
60
|
+
- point: a js array of numbers (i.e. `[5, 6]`)
|
|
61
|
+
- ray: a js array of two points (i.e. `[[5, 6], [1, 2]]`)
|
|
62
|
+
- line: a js array of two points (i.e. `[[5, 6], [1, 2]]`)
|
|
63
|
+
|
|
64
|
+
kmath functions usually take an argument of the corresponding type as
|
|
65
|
+
the first parameter, and other parameters afterwards. For example, to
|
|
66
|
+
rotate the point `[1, 1]` by 90 degrees around `[0, 0]`, one might use:
|
|
67
|
+
|
|
68
|
+
kmath.point.rotateDeg([1, 1], 90, [0, 0])
|
|
69
|
+
|
|
70
|
+
Documentation for specific functions for each type is provided below.
|
|
71
|
+
|
|
72
|
+
## kmath.number
|
|
73
|
+
|
|
74
|
+
#### `number.DEFAULT_TOLERANCE === 1e-9`
|
|
75
|
+
|
|
76
|
+
The default tolerance to kmath functions.
|
|
77
|
+
|
|
78
|
+
#### `number.EPSILON === Math.pow(2, -42)`
|
|
79
|
+
|
|
80
|
+
A small number. Not machine epsilon, but a reasonable amount of error
|
|
81
|
+
more than generally accrued by doing repeated floating point math.
|
|
82
|
+
|
|
83
|
+
#### `number.is(maybeANumber)`
|
|
84
|
+
|
|
85
|
+
Returns true if the argument is a javascript number.
|
|
86
|
+
|
|
87
|
+
#### `number.equal(number1, number2, [tolerance])`
|
|
88
|
+
|
|
89
|
+
Compares whether number1 and number2 are equal to each other, within
|
|
90
|
+
a difference of tolerance, which defaults to `number.DEFAULT_TOLERANCE`.
|
|
91
|
+
|
|
92
|
+
#### `number.sign(aNumber, [tolerance])`
|
|
93
|
+
|
|
94
|
+
Returns 0 if the number is equal to 0 within `tolerance`, or -1 if the
|
|
95
|
+
number is less than 0, or 1 if the number is greater than 0.
|
|
96
|
+
|
|
97
|
+
#### `number.isInteger(aNumber, tolerance)`
|
|
98
|
+
|
|
99
|
+
Returns true if `aNumber` is within `tolerance` difference of an integer.
|
|
100
|
+
`tolerance` defaults to `number.DEFAULT_TOLERANCE`.
|
|
101
|
+
|
|
102
|
+
#### `number.round(aNumber, precision)`
|
|
103
|
+
|
|
104
|
+
Rounds `aNumber` to `precision` decimal places.
|
|
105
|
+
|
|
106
|
+
#### `number.roundTo(aNumber, increment)`
|
|
107
|
+
|
|
108
|
+
Rounds `aNumber` to the nearest `increment`.
|
|
109
|
+
|
|
110
|
+
For example, `number.roundTo(1.4, 0.5)` would return `1.5`
|
|
111
|
+
|
|
112
|
+
#### `number.floorTo(aNumber, increment)`
|
|
113
|
+
|
|
114
|
+
Returns the nearest multiple of `increment` that is no greater than
|
|
115
|
+
`aNumber`.
|
|
116
|
+
|
|
117
|
+
#### `number.ceilTo(aNumber, increment)`
|
|
118
|
+
|
|
119
|
+
Returns the nearest multiple of `increment` that is no smaller than
|
|
120
|
+
`aNumber`.
|
|
121
|
+
|
|
122
|
+
#### `number.toFraction(decimal, [tolerance], [maxDenominator])`
|
|
123
|
+
|
|
124
|
+
Returns an array containing two elements, `[n, d]`, a numerator and
|
|
125
|
+
denominator representing a fraction `n/d` that is within `tolerance`
|
|
126
|
+
of `decimal`.
|
|
127
|
+
|
|
128
|
+
If no fraction with a denominator less than or equal to `maxDenominator`
|
|
129
|
+
is found, `[decimal, 1]` is returned.
|
|
130
|
+
|
|
131
|
+
`tolerance` defaults to `number.EPSILON`. `maxDenominator` defaults to
|
|
132
|
+
`1000`.
|
|
133
|
+
|
|
134
|
+
## kmath.vector
|
|
135
|
+
|
|
136
|
+
#### `vector.is(maybeAVector, [dimension])`
|
|
137
|
+
|
|
138
|
+
Returns true if `maybeAVector` is an array of numbers. If `dimension` is specified,
|
|
139
|
+
only returns true if `maybeAVector` is a vector with dimension `dimension`.
|
|
140
|
+
|
|
141
|
+
#### `vector.equal(v1, v2, [tolerance])`
|
|
142
|
+
|
|
143
|
+
Returns true if `v1` and `v2` are equal within `tolerance`. If `tolerance`
|
|
144
|
+
is not specified, `kmath.number.DEFAULT_TOLERANCE` is used. Each dimension
|
|
145
|
+
is compared individually, rather than comparing length and direction.
|
|
146
|
+
|
|
147
|
+
If `v1` and `v2` have different lengths, this function returns `false`.
|
|
148
|
+
|
|
149
|
+
kmath.vector.equal([1, 2], [1, 3])
|
|
150
|
+
=> false
|
|
151
|
+
kmath.vector.equal([1, 2], [1, 2, 3])
|
|
152
|
+
=> false
|
|
153
|
+
kmath.vector.equal([1, 2], [1, 2])
|
|
154
|
+
=> true
|
|
155
|
+
|
|
156
|
+
#### `vector.codirectional(v1, v2, [tolerance])`
|
|
157
|
+
|
|
158
|
+
Returns true if `v1` and `v2` have the same direction within `tolerance`.
|
|
159
|
+
If `tolerance` is unspecified, `kmath.number.DEFAULT_TOLERANCE` is used.
|
|
160
|
+
Note that tolerance is checked after normalization.
|
|
161
|
+
|
|
162
|
+
If `v1` and `v2` are different lengths, this function returns `false`,
|
|
163
|
+
regardless of whether they are codirectional in the existing dimensions.
|
|
164
|
+
|
|
165
|
+
This function defines the zero-vector as trivially codirectional with
|
|
166
|
+
every vector.
|
|
167
|
+
|
|
168
|
+
kmath.vector.codirectional([1, 2], [2, 4])
|
|
169
|
+
=> true
|
|
170
|
+
kmath.vector.codirectinoal([1, 2], [0, 0])
|
|
171
|
+
=> true
|
|
172
|
+
kmath.vector.codirectional([1, 2], [1, 2, 0])
|
|
173
|
+
=> false
|
|
174
|
+
kmath.vector.codirectional([1, 2], [-2, -4])
|
|
175
|
+
=> false
|
|
176
|
+
|
|
177
|
+
#### `vector.colinear(v1, v2, [tolerance])`
|
|
178
|
+
|
|
179
|
+
Returns true if `v1` and `v2` lie along the same line, regardless of
|
|
180
|
+
direction. This is equivalent to either `v1` and `v2` being codirectional,
|
|
181
|
+
or `v1` and `-v2` being codirectional, or whether there is some
|
|
182
|
+
`scaleFactor` such that `vector.equal(vector.scale(v1, scaleFactor), v2)`
|
|
183
|
+
is true.
|
|
184
|
+
|
|
185
|
+
kmath.vector.colinear([1, 2], [-2, -4])
|
|
186
|
+
=> true
|
|
187
|
+
|
|
188
|
+
#### `vector.normalize(v)`
|
|
189
|
+
|
|
190
|
+
Scales the cartesian vector `v` to be `1` unit long.
|
|
191
|
+
|
|
192
|
+
#### `vector.length(v)`
|
|
193
|
+
|
|
194
|
+
Returns the length of the cartesian vector `v`.
|
|
195
|
+
|
|
196
|
+
#### `vector.dot(v1, v2)`
|
|
197
|
+
|
|
198
|
+
Returns the dot product of cartesian vectors `v1` and `v2`.
|
|
199
|
+
|
|
200
|
+
#### `vector.add(*vectors)`
|
|
201
|
+
|
|
202
|
+
Adds multiple cartesian vectors together.
|
|
203
|
+
|
|
204
|
+
kmath.vector.add([1, 2], [3, 4])
|
|
205
|
+
=> [4, 6]
|
|
206
|
+
|
|
207
|
+
#### `vector.subtract(v1, v2)`
|
|
208
|
+
|
|
209
|
+
Subtracts the cartesian vector `v2` from the cartesian vector `v1`.
|
|
210
|
+
|
|
211
|
+
kmath.vector.subtract([4, 6], [1, 2])
|
|
212
|
+
=> [3, 4]
|
|
213
|
+
|
|
214
|
+
#### `vector.negate(v)`
|
|
215
|
+
|
|
216
|
+
Negates the cartesian vector `v`. This has the same effect as scaling
|
|
217
|
+
`v` by `-1` or reversing the direction of `v`.
|
|
218
|
+
|
|
219
|
+
#### `vector.scale(v, scalar)`
|
|
220
|
+
|
|
221
|
+
Scales the cartesian vector `v` by `scalar`.
|
|
222
|
+
|
|
223
|
+
kmath.vector.scale([1, 2], 2)
|
|
224
|
+
=> [2, 4]
|
|
225
|
+
|
|
226
|
+
#### `vector.polarRadFromCart(v)`
|
|
227
|
+
|
|
228
|
+
Returns a polar vector `[length, angle]` from the two-dimensional cartesian
|
|
229
|
+
vector `v`, where `angle` is measured in radians.
|
|
230
|
+
|
|
231
|
+
kmath.vector.polarRadFromCart([1, 1])
|
|
232
|
+
=> [1.4142135623730951, 0.7853981633974483]
|
|
233
|
+
|
|
234
|
+
#### `vector.polarDegFromCart(v)`
|
|
235
|
+
|
|
236
|
+
Returns a polar vector `[length, angle]` from the two-dimensional cartesian
|
|
237
|
+
vector `v`, where `angle` is measured in degrees.
|
|
238
|
+
|
|
239
|
+
kmath.vector.polarDegFromCart([0, 2])
|
|
240
|
+
=> [2, 90]
|
|
241
|
+
|
|
242
|
+
#### `vector.cartFromPolarRad(polar)` or `vector.cartFromPolarRad(length, angle)`
|
|
243
|
+
|
|
244
|
+
Returns a two-dimensional cartesian vector from the polar vector input,
|
|
245
|
+
where the input angle is measured in radians.
|
|
246
|
+
|
|
247
|
+
kmath.vector.cartFromPolarRad([2, Math.PI])
|
|
248
|
+
=> [-2, 0] // Note: a very small nonzero number is actually returned here,
|
|
249
|
+
// due to numerical inaccuracy.
|
|
250
|
+
kmath.vector.cartFromPolarRad(Math.pow(2, 0.5), Math.PI/4)
|
|
251
|
+
=> [1, 1]
|
|
252
|
+
|
|
253
|
+
#### `vector.cartFromPolarDeg(polar)` or `vector.cartFromPolarDeg(length, angle)`
|
|
254
|
+
|
|
255
|
+
Returns a two-dimensional cartesian vector from the polar vector input,
|
|
256
|
+
where the input angle is measured in degrees.
|
|
257
|
+
|
|
258
|
+
kmath.vector.cartFromPolarRad([2, 90])
|
|
259
|
+
=> [-2, 0] // Note: a very small nonzero number is actually returned here,
|
|
260
|
+
// due to numerical inaccuracy.
|
|
261
|
+
kmath.vector.cartFromPolarRad(Math.pow(2, 0.5), 45)
|
|
262
|
+
=> [1, 1]
|
|
263
|
+
|
|
264
|
+
#### `vector.rotateRad(v, angle)`
|
|
265
|
+
|
|
266
|
+
Returns the rotation of the cartesian vector `v` by `angle` radians.
|
|
267
|
+
|
|
268
|
+
#### `vector.rotateDeg(v, angle)`
|
|
269
|
+
|
|
270
|
+
Returns the rotation of the cartesian vector `v` by `angle` degrees.
|
|
271
|
+
|
|
272
|
+
#### `vector.angleRad(v1, v2)`
|
|
273
|
+
|
|
274
|
+
Returns the angle between the directions of cartesian vectors
|
|
275
|
+
`v1` and `v2` in radians.
|
|
276
|
+
|
|
277
|
+
#### `vector.angleDeg(v1, v2)`
|
|
278
|
+
|
|
279
|
+
Returns the angle between the directions of cartesian vectors
|
|
280
|
+
`v1` and `v2` in radians.
|
|
281
|
+
|
|
282
|
+
#### `vector.projection(v1, v2)`
|
|
283
|
+
|
|
284
|
+
Returns the projection of `v1` along the direction of `v2`
|
|
285
|
+
|
|
286
|
+
#### `vector.round(v, precision)`
|
|
287
|
+
|
|
288
|
+
Rounds each dimension of `v` to `precision` decimal places.
|
|
289
|
+
|
|
290
|
+
#### `vector.roundTo(v, increment)`
|
|
291
|
+
|
|
292
|
+
Rounds each dimension of `v` to the nearest `increment`.
|
|
293
|
+
|
|
294
|
+
#### `vector.floorTo(v, increment)`
|
|
295
|
+
|
|
296
|
+
Floors each dimension of `v` to the nearest `increment`.
|
|
297
|
+
|
|
298
|
+
#### `vector.ceilTo(v, increment)`
|
|
299
|
+
|
|
300
|
+
Ceils each dimension of `v` to the nearest `increment`.
|
|
301
|
+
|
|
302
|
+
## kmath.point
|
|
303
|
+
|
|
304
|
+
#### `point.is(maybeAPoint, [length])`
|
|
305
|
+
|
|
306
|
+
Returns true if `maybeAPoint` is an array of numbers. If length is specified,
|
|
307
|
+
only returns true if `maybeAPoint` is a point of dimension `length`.
|
|
308
|
+
|
|
309
|
+
#### `point.equal(p1, p2, [tolerance])`
|
|
310
|
+
|
|
311
|
+
Returns true if `p1` and `p2` are equal within `tolerance`. If `tolerance`
|
|
312
|
+
is not specified, `kmath.number.DEFAULT_TOLERANCE` is used. Each dimension
|
|
313
|
+
is compared individually.
|
|
314
|
+
|
|
315
|
+
If `p1` and `p2` have different lengths, this function returns `false`.
|
|
316
|
+
|
|
317
|
+
kmath.point.equal([1, 2], [1, 3])
|
|
318
|
+
=> false
|
|
319
|
+
kmath.point.equal([1, 2], [1, 2, 3])
|
|
320
|
+
=> false
|
|
321
|
+
kmath.point.equal([1, 2], [1, 2])
|
|
322
|
+
=> true
|
|
323
|
+
|
|
324
|
+
#### `point.addVector(p, *vectors)` or `point.addVectors(p, *vectors)`
|
|
325
|
+
|
|
326
|
+
Returns the point created by adding the cartesian vectors `*vectors`
|
|
327
|
+
to the cartesian point `p`.
|
|
328
|
+
|
|
329
|
+
#### `point.subtractVector(p, v)`
|
|
330
|
+
|
|
331
|
+
Returns the point created by subtracting the cartesian vectors `v`
|
|
332
|
+
to the cartesian point `p`.
|
|
333
|
+
|
|
334
|
+
#### `point.distanceToPoint(p1, p2)`
|
|
335
|
+
|
|
336
|
+
Returns the distance between `p1` and `p2`.
|
|
337
|
+
|
|
338
|
+
#### `point.distanceToLine(p, theLine)`
|
|
339
|
+
|
|
340
|
+
Returns the distance between `p` and the line `theLine`.
|
|
341
|
+
|
|
342
|
+
For example, to find the distance from the origin to the
|
|
343
|
+
`y = 5` line, one could write:
|
|
344
|
+
|
|
345
|
+
kmath.point.distanceToLine([0, 0], [[-1, 5], [1, 5]])
|
|
346
|
+
=> 5
|
|
347
|
+
|
|
348
|
+
#### `point.reflectOverLine(p, theLine)`
|
|
349
|
+
|
|
350
|
+
Returns the reflection of `p` over the line `theLine`.
|
|
351
|
+
|
|
352
|
+
For example, to reflect the origin over the line `y = 5`,
|
|
353
|
+
one could write:
|
|
354
|
+
|
|
355
|
+
kmath.point.reflectOverLine([0, 0], [[-1, 5], [1, 5]])
|
|
356
|
+
=> [0, 10]
|
|
357
|
+
|
|
358
|
+
#### `point.compare(p1, p2, [equalityTolerance])`
|
|
359
|
+
|
|
360
|
+
Compares two points, returning -1, 0, or 1, for use with
|
|
361
|
+
Array.prototype.sort
|
|
362
|
+
|
|
363
|
+
Note: This technically doesn't satisfy the total-ordering
|
|
364
|
+
requirements of Array.prototype.sort unless equalityTolerance
|
|
365
|
+
is 0. In some cases very close points that compare within a
|
|
366
|
+
few equalityTolerances could appear in the wrong order.
|
|
367
|
+
|
|
368
|
+
#### `point.polarRadFromCart(p)`
|
|
369
|
+
|
|
370
|
+
Returns a polar point `[length, angle]` from the two-dimensional cartesian
|
|
371
|
+
point `v`, where `angle` is measured in radians.
|
|
372
|
+
|
|
373
|
+
kmath.point.polarRadFromCart([1, 1])
|
|
374
|
+
=> [1.4142135623730951, 0.7853981633974483]
|
|
375
|
+
|
|
376
|
+
#### `point.polarDegFromCart(p)`
|
|
377
|
+
|
|
378
|
+
Returns a polar point `[length, angle]` from the two-dimensional cartesian
|
|
379
|
+
point `v`, where `angle` is measured in degrees.
|
|
380
|
+
|
|
381
|
+
kmath.point.polarDegFromCart([0, 2])
|
|
382
|
+
=> [2, 90]
|
|
383
|
+
|
|
384
|
+
#### `point.cartFromPolarRad(polar)` or `point.cartFromPolarRad(length, angle)`
|
|
385
|
+
|
|
386
|
+
Returns a two-dimensional cartesian point from the polar point input,
|
|
387
|
+
where the input angle is measured in radians.
|
|
388
|
+
|
|
389
|
+
kmath.point.cartFromPolarRad([2, Math.PI])
|
|
390
|
+
=> [-2, 0] // Note: a very small nonzero number is actually returned here,
|
|
391
|
+
// due to numerical inaccuracy.
|
|
392
|
+
kmath.point.cartFromPolarRad(Math.pow(2, 0.5), Math.PI/4)
|
|
393
|
+
=> [1, 1]
|
|
394
|
+
|
|
395
|
+
#### `point.cartFromPolarDeg(polar)` or `point.cartFromPolarDeg(length, angle)`
|
|
396
|
+
|
|
397
|
+
Returns a two-dimensional cartesian point from the polar point input,
|
|
398
|
+
where the input angle is measured in degrees.
|
|
399
|
+
|
|
400
|
+
kmath.point.cartFromPolarRad([2, 90])
|
|
401
|
+
=> [-2, 0] // Note: a very small nonzero number is actually returned here,
|
|
402
|
+
// due to numerical inaccuracy.
|
|
403
|
+
kmath.point.cartFromPolarRad(Math.pow(2, 0.5), 45)
|
|
404
|
+
=> [1, 1]
|
|
405
|
+
|
|
406
|
+
#### `point.rotateRad(p, angle, center)`
|
|
407
|
+
|
|
408
|
+
Returns the rotation of the two-dimensional point `v` by `angle` radians
|
|
409
|
+
around the point `center`
|
|
410
|
+
|
|
411
|
+
#### `point.rotateDeg(p, angle, center)`
|
|
412
|
+
|
|
413
|
+
Returns the rotation of the two-dimensional point `v` by `angle` degrees
|
|
414
|
+
around the point `center`.
|
|
415
|
+
|
|
416
|
+
#### `point.round(p, precision)`
|
|
417
|
+
|
|
418
|
+
Rounds each dimension of `p` to `precision` decimal places.
|
|
419
|
+
|
|
420
|
+
#### `point.roundTo(p, increment)`
|
|
421
|
+
|
|
422
|
+
Rounds each dimension of `p` to the nearest `increment`.
|
|
423
|
+
|
|
424
|
+
#### `point.floorTo(p, increment)`
|
|
425
|
+
|
|
426
|
+
Floors each dimension of `p` to the nearest `increment`.
|
|
427
|
+
|
|
428
|
+
#### `point.ceilTo(p, increment)`
|
|
429
|
+
|
|
430
|
+
Ceils each dimension of `p` to the nearest `increment`.
|
|
431
|
+
|
|
432
|
+
## kmath.ray
|
|
433
|
+
|
|
434
|
+
#### `ray.equal(r1, r2, [tolerance])`
|
|
435
|
+
|
|
436
|
+
Returns true if rays `r1` and `r2` are equal within `tolerance`.
|
|
437
|
+
|
|
438
|
+
If unspecified, `tolerance` defaults to `kmath.number.DEFAULT_TOLERANCE`.
|
|
439
|
+
|
|
440
|
+
## kmath.line
|
|
441
|
+
|
|
442
|
+
#### `line.equal(line1, line2, [tolerance])`
|
|
443
|
+
|
|
444
|
+
Returns true if lines `line1` and `line2` are equal within `tolerance`.
|
|
445
|
+
|
|
446
|
+
If unspecified, `tolerance` defaults to `kmath.number.DEFAULT_TOLERANCE`.
|
|
447
|
+
|
|
448
|
+
#### `line.midpoint(theLine)`
|
|
449
|
+
|
|
450
|
+
Returns the midpoint of the line `theLine`.
|
|
451
|
+
|
|
452
|
+
kmath.line.midpoint([[0, 5], [5, 0]])
|
|
453
|
+
=> [2.5, 2.5]
|
|
454
|
+
|
|
455
|
+
#### `line.distanceToPoint(theLine, p)`
|
|
456
|
+
|
|
457
|
+
Returns the distance between `theLine` and point `p`.
|
|
458
|
+
|
|
459
|
+
#### `line.reflectPoint(theLine, p)`
|
|
460
|
+
|
|
461
|
+
Returns the reflection of `p` over `theLine`.
|
|
462
|
+
|
|
463
|
+
## License
|
|
464
|
+
|
|
465
|
+
MIT. See the LICENSE file for more information.
|
package/dist/es/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import r from"underscore";var n=Math.pow(2,-42);function t(n){return r.isNumber(n)&&!r.isNaN(n)}function o(r,n,t){return null==r||null==n?r===n:r===n||(null==t&&(t=1e-9),Math.abs(r-n)<t)}function e(r,n){var t=Math.pow(10,n);return Math.round(r*t)/t}function u(r,n){return Math.round(r/n)*n}function a(r,n){return Math.floor(r/n)*n}function i(r,n){return Math.ceil(r/n)*n}var c=Object.freeze({__proto__:null,DEFAULT_TOLERANCE:1e-9,EPSILON:n,is:t,equal:o,sign:function(r,n){return o(r,0,n)?0:Math.abs(r)/r},isInteger:function(r,n){return o(Math.round(r),r,n)},round:e,roundTo:u,floorTo:a,ceilTo:i,toFraction:function(r){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:n,e=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1e3,u=[1,0],a=[0,1],i=Math.floor(r),c=r-i;a[0]<=e;){if(o(u[0]/a[0],r,t))return[u[0],a[0]];u=[i*u[0]+u[1],u[0]],a=[i*a[0]+a[1],a[0]],c=1/c-(i=Math.floor(1/c))}return[r,1]}});function f(r){return r.reduce(((r,n)=>r+n),0)}function l(r){return r.reduce(((r,n)=>r*n),1)}function d(n,o){return!!r.isArray(n)&&((void 0===o||n.length===o)&&n.every(t))}function h(r){return _(r,1/v(r))}function v(r){return Math.sqrt(p(r,r))}function p(n,t){return f(r.zip(n,t).map(l))}function g(){var n=r.zip(...arguments);return n.map(f)}function m(n,t){return r.zip(n,t).map((r=>r[0]-r[1]))}function s(r){return r.map((r=>-r))}function _(r,n){return r.map((r=>r*n))}function M(n,t,e){return r.zip(n,t).every((r=>o(r[0],r[1],e)))}function T(r,n,t){return!(!o(v(r),0,t)&&!o(v(n),0,t))||M(r=h(r),n=h(n),t)}function P(r,n,t){return T(r,n,t)||T(r,s(n),t)}function b(r){var n=v(r),t=Math.atan2(r[1],r[0]);return t<0&&(t+=2*Math.PI),[n,t]}function z(r){var n=b(r);return[n[0],180*n[1]/Math.PI]}function F(r){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return[r*Math.cos(n),r*Math.sin(n)]}function D(r){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return F(r,n*Math.PI/180)}function O(r,n){var t=b(r),o=t[1]+n;return F(t[0],o)}function R(r,n){var t=z(r),o=t[1]+n;return D(t[0],o)}function j(r,n){return Math.acos(p(r,n)/(v(r)*v(n)))}function q(r,n){return _(n,p(r,n)/p(n,n))}function I(r,n){return r.map(((r,t)=>e(r,n[t]||n)))}function C(r,n){return r.map(((r,t)=>u(r,n[t]||n)))}function L(r,n){return r.map(((r,t)=>a(r,n[t]||n)))}function N(r,n){return r.map(((r,t)=>i(r,n[t]||n)))}var E=Object.freeze({__proto__:null,is:d,normalize:h,length:v,dot:p,add:g,subtract:m,negate:s,scale:_,equal:M,codirectional:T,collinear:P,polarRadFromCart:b,polarDegFromCart:z,cartFromPolarRad:F,cartFromPolarDeg:D,rotateRad:O,rotateDeg:R,angleRad:j,angleDeg:function(r,n){return 180*j(r,n)/Math.PI},projection:q,round:I,roundTo:C,floorTo:L,ceilTo:N});function y(r,n){var t=m(n[1],n[0]),o=m(r,n[0]);return v(m(q(o,t),o))}function A(r,n){var t=m(n[1],n[0]),o=m(r,n[0]),e=m(_(q(o,t),2),o);return g(n[0],e)}var V=d,w=g,x=g,S=m,U=M,k=b,B=z,G=F,H=D,J=I,K=C,Q=L,W=N,X=Object.freeze({__proto__:null,rotateRad:function(r,n,t){return void 0===t?O(r,n):g(t,O(m(r,t),n))},rotateDeg:function(r,n,t){return void 0===t?R(r,n):g(t,R(m(r,t),n))},distanceToPoint:function(r,n){return v(m(r,n))},distanceToLine:y,reflectOverLine:A,compare:function(r,n,t){if(r.length!==n.length)return r.length-n.length;for(var e=0;e<r.length;e++)if(!o(r[e],n[e],t))return r[e]-n[e];return 0},is:V,addVector:w,addVectors:x,subtractVector:S,equal:U,polarRadFromCart:k,polarDegFromCart:B,cartFromPolarRad:G,cartFromPolarDeg:H,round:J,roundTo:K,floorTo:Q,ceilTo:W});var Y=Object.freeze({__proto__:null,distanceToPoint:function(r,n){return y(n,r)},reflectPoint:function(r,n){return A(n,r)},midpoint:function(r){return[(r[0][0]+r[1][0])/2,(r[0][1]+r[1][1])/2]},equal:function(r,n,t){var o=m(r[1],r[0]);return!!P(o,m(n[1],n[0]),t)&&(!!U(r[0],n[0])||P(o,m(n[0],r[0]),t))}});var Z=Object.freeze({__proto__:null,equal:function(r,n,t){var o=m(r[1],r[0]),e=m(n[1],n[0]),u=U(r[0],n[0]),a=T(o,e,t);return u&&a}});export{Y as line,c as number,X as point,Z as ray,E as vector};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/number.js","../../src/vector.js","../../src/point.js","../../src/line.js","../../src/ray.js"],"sourcesContent":["// @flow\n/**\n * Number Utils\n * A number is a js-number, e.g. 5.12\n */\n\nimport _ from \"underscore\";\n\nexport const DEFAULT_TOLERANCE: number = 1e-9;\n\n// TODO: Should this just be Number.Epsilon\nexport const EPSILON: number = Math.pow(2, -42);\n\nexport function is(x: any): boolean {\n return _.isNumber(x) && !_.isNaN(x);\n}\n\nexport function equal(x: number, y: number, tolerance?: number): boolean {\n // Checking for undefined makes this function behave nicely\n // with vectors of different lengths that are _.zip'd together\n if (x == null || y == null) {\n return x === y;\n }\n // We check === here so that +/-Infinity comparisons work correctly\n if (x === y) {\n return true;\n }\n if (tolerance == null) {\n tolerance = DEFAULT_TOLERANCE;\n }\n return Math.abs(x - y) < tolerance;\n}\n\nexport function sign(\n x: number,\n tolerance?: number,\n): number /* Should be: 0 | 1 | -1 */ {\n return equal(x, 0, tolerance) ? 0 : Math.abs(x) / x;\n}\n\nexport function isInteger(num: number, tolerance?: number): boolean {\n return equal(Math.round(num), num, tolerance);\n}\n\n// Round a number to a certain number of decimal places\nexport function round(num: number, precision: number): number {\n const factor = Math.pow(10, precision);\n return Math.round(num * factor) / factor;\n}\n\n// Round num to the nearest multiple of increment\n// i.e. roundTo(83, 5) -> 85\nexport function roundTo(num: number, increment: number): number {\n return Math.round(num / increment) * increment;\n}\n\nexport function floorTo(num: number, increment: number): number {\n return Math.floor(num / increment) * increment;\n}\n\nexport function ceilTo(num: number, increment: number): number {\n return Math.ceil(num / increment) * increment;\n}\n\n/**\n * toFraction\n *\n * Returns a [numerator, denominator] array rational representation\n * of `decimal`\n *\n * See http://en.wikipedia.org/wiki/Continued_fraction for implementation\n * details\n *\n * toFraction(4/8) => [1, 2]\n * toFraction(0.66) => [33, 50]\n * toFraction(0.66, 0.01) => [2/3]\n * toFraction(283 + 1/3) => [850, 3]\n */\nexport function toFraction(\n decimal: number,\n tolerance: number = EPSILON, // can't be 0\n maxDenominator: number = 1000,\n): [number, number] {\n // Initialize everything to compute successive terms of\n // continued-fraction approximations via recurrence relation\n let n = [1, 0];\n let d = [0, 1];\n let a = Math.floor(decimal);\n let rem = decimal - a;\n\n while (d[0] <= maxDenominator) {\n if (equal(n[0] / d[0], decimal, tolerance)) {\n return [n[0], d[0]];\n }\n n = [a * n[0] + n[1], n[0]];\n d = [a * d[0] + d[1], d[0]];\n a = Math.floor(1 / rem);\n rem = 1 / rem - a;\n }\n\n // We failed to find a nice rational representation,\n // so return an irrational \"fraction\"\n return [decimal, 1];\n}\n","// @flow\n/**\n * Vector Utils\n * A vector is an array of numbers e.g. [0, 3, 4].\n */\n\nimport _ from \"underscore\";\nimport * as knumber from \"./number.js\";\n\nfunction arraySum(array: $ReadOnlyArray<number>): number {\n return array.reduce((memo, arg) => memo + arg, 0);\n}\n\nfunction arrayProduct(array: $ReadOnlyArray<number>): number {\n return array.reduce((memo, arg) => memo * arg, 1);\n}\n\nexport function is<T>(vec: $ReadOnlyArray<T>, dimension: number): boolean {\n if (!_.isArray(vec)) {\n return false;\n }\n if (dimension !== undefined && vec.length !== dimension) {\n return false;\n }\n return vec.every(knumber.is);\n}\n\n// Normalize to a unit vector\nexport function normalize(v: $ReadOnlyArray<number>): $ReadOnlyArray<number> {\n return scale(v, 1 / length(v));\n}\n\n// Length/magnitude of a vector\nexport function length(v: $ReadOnlyArray<number>): number {\n return Math.sqrt(dot(v, v));\n}\n// Dot product of two vectors\nexport function dot(\n a: $ReadOnlyArray<number>,\n b: $ReadOnlyArray<number>,\n): number {\n // $FlowFixMe[incompatible-call] underscore doesn't like $ReadOnlyArray\n const zipped = _.zip(a, b);\n const multiplied = zipped.map(arrayProduct);\n return arraySum(multiplied);\n}\n\n/* vector-add multiple [x, y] coords/vectors\n *\n * add([1, 2], [3, 4]) -> [4, 6]\n */\nexport function add(\n ...vecs: $ReadOnlyArray<$ReadOnlyArray<number>>\n): $ReadOnlyArray<number> {\n // $FlowFixMe[incompatible-call] underscore doesn't like $ReadOnlyArray\n const zipped = _.zip(...vecs);\n return zipped.map(arraySum);\n}\n\nexport function subtract(\n v1: $ReadOnlyArray<number>,\n v2: $ReadOnlyArray<number>,\n): $ReadOnlyArray<number> {\n // $FlowFixMe[incompatible-call] underscore doesn't like $ReadOnlyArray\n return _.zip(v1, v2).map((dim) => dim[0] - dim[1]);\n}\n\nexport function negate(v: $ReadOnlyArray<number>): $ReadOnlyArray<number> {\n return v.map((x) => {\n return -x;\n });\n}\n\n// Scale a vector\nexport function scale(\n v1: $ReadOnlyArray<number>,\n scalar: number,\n): $ReadOnlyArray<number> {\n return v1.map((x) => {\n return x * scalar;\n });\n}\n\nexport function equal(\n v1: $ReadOnlyArray<number>,\n v2: $ReadOnlyArray<number>,\n tolerance?: number,\n): boolean {\n // _.zip will nicely deal with the lengths, going through\n // the length of the longest vector. knumber.equal then\n // returns false for any number compared to the undefined\n // passed in if one of the vectors is shorter.\n // $FlowFixMe[incompatible-call] underscore doesn't like $ReadOnlyArray\n return _.zip(v1, v2).every((pair) =>\n knumber.equal(pair[0], pair[1], tolerance),\n );\n}\n\nexport function codirectional(\n v1: $ReadOnlyArray<number>,\n v2: $ReadOnlyArray<number>,\n tolerance?: number,\n): boolean {\n // The origin is trivially codirectional with all other vectors.\n // This gives nice semantics for codirectionality between points when\n // comparing their difference vectors.\n if (\n knumber.equal(length(v1), 0, tolerance) ||\n knumber.equal(length(v2), 0, tolerance)\n ) {\n return true;\n }\n\n v1 = normalize(v1);\n v2 = normalize(v2);\n\n return equal(v1, v2, tolerance);\n}\n\nexport function collinear(\n v1: $ReadOnlyArray<number>,\n v2: $ReadOnlyArray<number>,\n tolerance?: number,\n): boolean {\n return (\n codirectional(v1, v2, tolerance) ||\n codirectional(v1, negate(v2), tolerance)\n );\n}\n\n// Convert a cartesian coordinate into a radian polar coordinate\nexport function polarRadFromCart(\n v: $ReadOnlyArray<number>,\n): $ReadOnlyArray<number> {\n const radius = length(v);\n let theta = Math.atan2(v[1], v[0]);\n\n // Convert angle range from [-pi, pi] to [0, 2pi]\n if (theta < 0) {\n theta += 2 * Math.PI;\n }\n\n return [radius, theta];\n}\n\n// Converts a cartesian coordinate into a degree polar coordinate\nexport function polarDegFromCart(\n v: $ReadOnlyArray<number>,\n): $ReadOnlyArray<number> /* TODO: convert to tuple/Point */ {\n const polar = polarRadFromCart(v);\n return [polar[0], (polar[1] * 180) / Math.PI];\n}\n\n/* Convert a polar coordinate into a cartesian coordinate\n *\n * Examples:\n * cartFromPolarRad(5, Math.PI)\n * cartFromPolarRad([5, Math.PI])\n */\nexport function cartFromPolarRad(\n radius: number,\n theta?: number = 0,\n): $ReadOnlyArray<number> /* TODO: convert to tuple/Point */ {\n return [radius * Math.cos(theta), radius * Math.sin(theta)];\n}\n\n/* Convert a polar coordinate into a cartesian coordinate\n *\n * Examples:\n * cartFromPolarDeg(5, 30)\n * cartFromPolarDeg([5, 30])\n */\nexport function cartFromPolarDeg(\n radius: number,\n theta?: number = 0,\n): $ReadOnlyArray<number> {\n return cartFromPolarRad(radius, (theta * Math.PI) / 180);\n}\n\n// Rotate vector\nexport function rotateRad(\n v: $ReadOnlyArray<number>,\n theta: number,\n): $ReadOnlyArray<number> {\n const polar = polarRadFromCart(v);\n const angle = polar[1] + theta;\n return cartFromPolarRad(polar[0], angle);\n}\n\nexport function rotateDeg(\n v: $ReadOnlyArray<number>,\n theta: number,\n): $ReadOnlyArray<number> {\n const polar = polarDegFromCart(v);\n const angle = polar[1] + theta;\n return cartFromPolarDeg(polar[0], angle);\n}\n\n// Angle between two vectors\nexport function angleRad(\n v1: $ReadOnlyArray<number>,\n v2: $ReadOnlyArray<number>,\n): number {\n return Math.acos(dot(v1, v2) / (length(v1) * length(v2)));\n}\n\nexport function angleDeg(\n v1: $ReadOnlyArray<number>,\n v2: $ReadOnlyArray<number>,\n): number {\n return (angleRad(v1, v2) * 180) / Math.PI;\n}\n\n// Vector projection of v1 onto v2\nexport function projection(\n v1: $ReadOnlyArray<number>,\n v2: $ReadOnlyArray<number>,\n): $ReadOnlyArray<number> {\n const scalar = dot(v1, v2) / dot(v2, v2);\n return scale(v2, scalar);\n}\n\n// Round each number to a certain number of decimal places\nexport function round(\n vec: $ReadOnlyArray<number>,\n precision: $ReadOnlyArray<number> | number,\n): $ReadOnlyArray<number> {\n return vec.map((elem, i) =>\n // $FlowFixMe[prop-missing]\n // $FlowFixMe[incompatible-call]\n knumber.round(elem, precision[i] || precision),\n );\n}\n\n// Round each number to the nearest increment\nexport function roundTo(\n vec: $ReadOnlyArray<number>,\n increment: $ReadOnlyArray<number> | number,\n): $ReadOnlyArray<number> {\n return vec.map((elem, i) =>\n // $FlowFixMe[prop-missing]\n // $FlowFixMe[incompatible-call]\n knumber.roundTo(elem, increment[i] || increment),\n );\n}\n\nexport function floorTo(\n vec: $ReadOnlyArray<number>,\n increment: $ReadOnlyArray<number> | number,\n): $ReadOnlyArray<number> {\n return vec.map((elem, i) =>\n // $FlowFixMe[prop-missing]\n // $FlowFixMe[incompatible-call]\n knumber.floorTo(elem, increment[i] || increment),\n );\n}\n\nexport function ceilTo(\n vec: $ReadOnlyArray<number>,\n increment: $ReadOnlyArray<number> | number,\n): $ReadOnlyArray<number> {\n return vec.map((elem, i) =>\n // $FlowFixMe[prop-missing]\n // $FlowFixMe[incompatible-call]\n knumber.ceilTo(elem, increment[i] || increment),\n );\n}\n","// @flow\n/**\n * Point Utils\n * A point is an array of two numbers e.g. [0, 0].\n */\n\nimport _ from \"underscore\";\n\nimport * as kvector from \"./vector.js\";\nimport * as knumber from \"./number.js\";\n\n// A point, in 2D, 3D, or nD space.\nexport type Point = $ReadOnlyArray<number>;\n\n// Rotate point (around origin unless a center is specified)\nexport function rotateRad(point: Point, theta: number, center: Point): Point {\n if (center === undefined) {\n return kvector.rotateRad(point, theta);\n } else {\n return kvector.add(\n center,\n kvector.rotateRad(kvector.subtract(point, center), theta),\n );\n }\n}\n\nexport function rotateDeg(point: Point, theta: number, center: Point): Point {\n if (center === undefined) {\n return kvector.rotateDeg(point, theta);\n } else {\n return kvector.add(\n center,\n kvector.rotateDeg(kvector.subtract(point, center), theta),\n );\n }\n}\n\n// Distance between two points\nexport function distanceToPoint(point1: Point, point2: Point): number {\n return kvector.length(kvector.subtract(point1, point2));\n}\n\n// Distance between point and line\nexport function distanceToLine(point: Point, line: [Point, Point]): number {\n const lv = kvector.subtract(line[1], line[0]);\n const pv = kvector.subtract(point, line[0]);\n const projectedPv = kvector.projection(pv, lv);\n const distancePv = kvector.subtract(projectedPv, pv);\n return kvector.length(distancePv);\n}\n\n// Reflect point over line\nexport function reflectOverLine(\n point: Point,\n line: [Point, Point],\n): $ReadOnlyArray<number> /* TODO: convert to Point */ {\n const lv = kvector.subtract(line[1], line[0]);\n const pv = kvector.subtract(point, line[0]);\n const projectedPv = kvector.projection(pv, lv);\n const reflectedPv = kvector.subtract(kvector.scale(projectedPv, 2), pv);\n return kvector.add(line[0], reflectedPv);\n}\n\n/**\n * Compares two points, returning -1, 0, or 1, for use with\n * Array.prototype.sort\n *\n * Note: This technically doesn't satisfy the total-ordering\n * requirements of Array.prototype.sort unless equalityTolerance\n * is 0. In some cases very close points that compare within a\n * few equalityTolerances could appear in the wrong order.\n */\nexport function compare(\n point1: Point,\n point2: Point,\n equalityTolerance?: number,\n): number /* TODO: convert to -1 | 0 | 1 type */ {\n if (point1.length !== point2.length) {\n return point1.length - point2.length;\n }\n for (let i = 0; i < point1.length; i++) {\n if (!knumber.equal(point1[i], point2[i], equalityTolerance)) {\n return point1[i] - point2[i];\n }\n }\n return 0;\n}\n\n// Check if a value is a point\nexport const is = kvector.is;\n\n// Add and subtract vector(s)\nexport const addVector = kvector.add;\nexport const addVectors = kvector.add;\nexport const subtractVector = kvector.subtract;\nexport const equal = kvector.equal;\n\n// Convert from cartesian to polar and back\nexport const polarRadFromCart = kvector.polarRadFromCart;\nexport const polarDegFromCart = kvector.polarDegFromCart;\nexport const cartFromPolarRad = kvector.cartFromPolarRad;\nexport const cartFromPolarDeg = kvector.cartFromPolarDeg;\n\n// Rounding\nexport const round = kvector.round;\nexport const roundTo = kvector.roundTo;\nexport const floorTo = kvector.floorTo;\nexport const ceilTo = kvector.ceilTo;\n","// @flow\n/**\n * Line Utils\n * A line is an array of two points e.g. [[-5, 0], [5, 0]].\n */\n\nimport * as kpoint from \"./point.js\";\nimport * as kvector from \"./vector.js\";\n\nimport type {Point} from \"./point.js\";\n\nexport type Line = [Point, Point];\n\nexport function distanceToPoint(line: Line, point: Point): number {\n return kpoint.distanceToLine(point, line);\n}\n\nexport function reflectPoint(\n line: Line,\n point: Point,\n): $ReadOnlyArray<number> /* TODO: convert to Point */ {\n return kpoint.reflectOverLine(point, line);\n}\n\nexport function midpoint(line: Line): Point {\n return [(line[0][0] + line[1][0]) / 2, (line[0][1] + line[1][1]) / 2];\n}\n\nexport function equal(line1: Line, line2: Line, tolerance?: number): boolean {\n // TODO: A nicer implementation might just check collinearity of\n // vectors using underscore magick\n // Compare the directions of the lines\n const v1 = kvector.subtract(line1[1], line1[0]);\n const v2 = kvector.subtract(line2[1], line2[0]);\n if (!kvector.collinear(v1, v2, tolerance)) {\n return false;\n }\n // If the start point is the same for the two lines, then they are the same\n if (kpoint.equal(line1[0], line2[0])) {\n return true;\n }\n // Make sure that the direction to get from line1 to\n // line2 is the same as the direction of the lines\n const line1ToLine2Vector = kvector.subtract(line2[0], line1[0]);\n return kvector.collinear(v1, line1ToLine2Vector, tolerance);\n}\n","// @flow\n/**\n * Ray Utils\n * A ray (→) is an array of an endpoint and another point along the ray.\n * For example, [[0, 0], [1, 0]] is the ray starting at the origin and\n * traveling along the positive x-axis.\n */\n\nimport * as kvector from \"./vector.js\";\nimport * as kpoint from \"./point.js\";\n\nimport type {Point} from \"./point\";\n\nexport type Ray = [Point, Point];\n\nexport function equal(ray1: Ray, ray2: Ray, tolerance: number): boolean {\n // Compare the directions of the rays\n const v1 = kvector.subtract(ray1[1], ray1[0]);\n const v2 = kvector.subtract(ray2[1], ray2[0]);\n\n const sameOrigin = kpoint.equal(ray1[0], ray2[0]);\n const codirectional = kvector.codirectional(v1, v2, tolerance);\n\n return sameOrigin && codirectional;\n}\n"],"names":["EPSILON","Math","pow","is","x","_","isNumber","isNaN","equal","y","tolerance","abs","round","num","precision","factor","roundTo","increment","floorTo","floor","ceilTo","ceil","decimal","maxDenominator","n","d","a","rem","arraySum","array","reduce","memo","arg","arrayProduct","vec","dimension","isArray","undefined","length","every","knumber","normalize","v","scale","sqrt","dot","b","zip","map","add","zipped","subtract","v1","v2","dim","negate","scalar","pair","codirectional","collinear","polarRadFromCart","radius","theta","atan2","PI","polarDegFromCart","polar","cartFromPolarRad","cos","sin","cartFromPolarDeg","rotateRad","angle","rotateDeg","angleRad","acos","projection","elem","i","distanceToLine","point","line","lv","kvector","pv","reflectOverLine","reflectedPv","addVector","addVectors","subtractVector","center","point1","point2","equalityTolerance","kpoint","line1","line2","ray1","ray2","sameOrigin"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";function t(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}Object.defineProperty(exports,"__esModule",{value:!0});var n=t(require("underscore"));const r=Math.pow(2,-42);function e(t){return n.default.isNumber(t)&&!n.default.isNaN(t)}function o(t,n,r){return null==t||null==n?t===n:t===n||(null==r&&(r=1e-9),Math.abs(t-n)<r)}function u(t,n){const r=Math.pow(10,n);return Math.round(t*r)/r}function a(t,n){return Math.round(t/n)*n}function c(t,n){return Math.floor(t/n)*n}function i(t,n){return Math.ceil(t/n)*n}var f=Object.freeze({__proto__:null,DEFAULT_TOLERANCE:1e-9,EPSILON:r,is:e,equal:o,sign:function(t,n){return o(t,0,n)?0:Math.abs(t)/t},isInteger:function(t,n){return o(Math.round(t),t,n)},round:u,roundTo:a,floorTo:c,ceilTo:i,toFraction:function(t){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:r,e=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1e3,u=[1,0],a=[0,1],c=Math.floor(t),i=t-c;for(;a[0]<=e;){if(o(u[0]/a[0],t,n))return[u[0],a[0]];u=[c*u[0]+u[1],u[0]],a=[c*a[0]+a[1],a[0]],c=Math.floor(1/i),i=1/i-c}return[t,1]}});function l(t){return t.reduce(((t,n)=>t+n),0)}function d(t){return t.reduce(((t,n)=>t*n),1)}function s(t,r){return!!n.default.isArray(t)&&((void 0===r||t.length===r)&&t.every(e))}function p(t){return v(t,1/h(t))}function h(t){return Math.sqrt(g(t,t))}function g(t,r){return l(n.default.zip(t,r).map(d))}function _(){const t=n.default.zip(...arguments);return t.map(l)}function m(t,r){return n.default.zip(t,r).map((t=>t[0]-t[1]))}function M(t){return t.map((t=>-t))}function v(t,n){return t.map((t=>t*n))}function T(t,r,e){return n.default.zip(t,r).every((t=>o(t[0],t[1],e)))}function b(t,n,r){return!(!o(h(t),0,r)&&!o(h(n),0,r))||T(t=p(t),n=p(n),r)}function P(t,n,r){return b(t,n,r)||b(t,M(n),r)}function z(t){const n=h(t);let r=Math.atan2(t[1],t[0]);return r<0&&(r+=2*Math.PI),[n,r]}function F(t){const n=z(t);return[n[0],180*n[1]/Math.PI]}function O(t){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return[t*Math.cos(n),t*Math.sin(n)]}function j(t){let n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;return O(t,n*Math.PI/180)}function D(t,n){const r=z(t),e=r[1]+n;return O(r[0],e)}function R(t,n){const r=F(t),e=r[1]+n;return j(r[0],e)}function q(t,n){return Math.acos(g(t,n)/(h(t)*h(n)))}function x(t,n){return v(n,g(t,n)/g(n,n))}function y(t,n){return t.map(((t,r)=>u(t,n[r]||n)))}function I(t,n){return t.map(((t,r)=>a(t,n[r]||n)))}function C(t,n){return t.map(((t,r)=>c(t,n[r]||n)))}function L(t,n){return t.map(((t,r)=>i(t,n[r]||n)))}var N=Object.freeze({__proto__:null,is:s,normalize:p,length:h,dot:g,add:_,subtract:m,negate:M,scale:v,equal:T,codirectional:b,collinear:P,polarRadFromCart:z,polarDegFromCart:F,cartFromPolarRad:O,cartFromPolarDeg:j,rotateRad:D,rotateDeg:R,angleRad:q,angleDeg:function(t,n){return 180*q(t,n)/Math.PI},projection:x,round:y,roundTo:I,floorTo:C,ceilTo:L});function E(t,n){const r=m(n[1],n[0]),e=m(t,n[0]);return h(m(x(e,r),e))}function A(t,n){const r=m(n[1],n[0]),e=m(t,n[0]),o=m(v(x(e,r),2),e);return _(n[0],o)}const V=s,w=_,S=_,U=m,k=T,B=z,G=F,H=O,J=j,K=y,Q=I,W=C,X=L;var Y=Object.freeze({__proto__:null,rotateRad:function(t,n,r){return void 0===r?D(t,n):_(r,D(m(t,r),n))},rotateDeg:function(t,n,r){return void 0===r?R(t,n):_(r,R(m(t,r),n))},distanceToPoint:function(t,n){return h(m(t,n))},distanceToLine:E,reflectOverLine:A,compare:function(t,n,r){if(t.length!==n.length)return t.length-n.length;for(let e=0;e<t.length;e++)if(!o(t[e],n[e],r))return t[e]-n[e];return 0},is:V,addVector:w,addVectors:S,subtractVector:U,equal:k,polarRadFromCart:B,polarDegFromCart:G,cartFromPolarRad:H,cartFromPolarDeg:J,round:K,roundTo:Q,floorTo:W,ceilTo:X});var Z=Object.freeze({__proto__:null,distanceToPoint:function(t,n){return E(n,t)},reflectPoint:function(t,n){return A(n,t)},midpoint:function(t){return[(t[0][0]+t[1][0])/2,(t[0][1]+t[1][1])/2]},equal:function(t,n,r){const e=m(t[1],t[0]);return!!P(e,m(n[1],n[0]),r)&&(!!k(t[0],n[0])||P(e,m(n[0],t[0]),r))}});var $=Object.freeze({__proto__:null,equal:function(t,n,r){const e=m(t[1],t[0]),o=m(n[1],n[0]),u=k(t[0],n[0]),a=b(e,o,r);return u&&a}});exports.line=Z,exports.number=f,exports.point=Y,exports.ray=$,exports.vector=N;
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/number.js","../src/vector.js","../src/point.js","../src/line.js","../src/ray.js"],"sourcesContent":["// @flow\n/**\n * Number Utils\n * A number is a js-number, e.g. 5.12\n */\n\nimport _ from \"underscore\";\n\nexport const DEFAULT_TOLERANCE: number = 1e-9;\n\n// TODO: Should this just be Number.Epsilon\nexport const EPSILON: number = Math.pow(2, -42);\n\nexport function is(x: any): boolean {\n return _.isNumber(x) && !_.isNaN(x);\n}\n\nexport function equal(x: number, y: number, tolerance?: number): boolean {\n // Checking for undefined makes this function behave nicely\n // with vectors of different lengths that are _.zip'd together\n if (x == null || y == null) {\n return x === y;\n }\n // We check === here so that +/-Infinity comparisons work correctly\n if (x === y) {\n return true;\n }\n if (tolerance == null) {\n tolerance = DEFAULT_TOLERANCE;\n }\n return Math.abs(x - y) < tolerance;\n}\n\nexport function sign(\n x: number,\n tolerance?: number,\n): number /* Should be: 0 | 1 | -1 */ {\n return equal(x, 0, tolerance) ? 0 : Math.abs(x) / x;\n}\n\nexport function isInteger(num: number, tolerance?: number): boolean {\n return equal(Math.round(num), num, tolerance);\n}\n\n// Round a number to a certain number of decimal places\nexport function round(num: number, precision: number): number {\n const factor = Math.pow(10, precision);\n return Math.round(num * factor) / factor;\n}\n\n// Round num to the nearest multiple of increment\n// i.e. roundTo(83, 5) -> 85\nexport function roundTo(num: number, increment: number): number {\n return Math.round(num / increment) * increment;\n}\n\nexport function floorTo(num: number, increment: number): number {\n return Math.floor(num / increment) * increment;\n}\n\nexport function ceilTo(num: number, increment: number): number {\n return Math.ceil(num / increment) * increment;\n}\n\n/**\n * toFraction\n *\n * Returns a [numerator, denominator] array rational representation\n * of `decimal`\n *\n * See http://en.wikipedia.org/wiki/Continued_fraction for implementation\n * details\n *\n * toFraction(4/8) => [1, 2]\n * toFraction(0.66) => [33, 50]\n * toFraction(0.66, 0.01) => [2/3]\n * toFraction(283 + 1/3) => [850, 3]\n */\nexport function toFraction(\n decimal: number,\n tolerance: number = EPSILON, // can't be 0\n maxDenominator: number = 1000,\n): [number, number] {\n // Initialize everything to compute successive terms of\n // continued-fraction approximations via recurrence relation\n let n = [1, 0];\n let d = [0, 1];\n let a = Math.floor(decimal);\n let rem = decimal - a;\n\n while (d[0] <= maxDenominator) {\n if (equal(n[0] / d[0], decimal, tolerance)) {\n return [n[0], d[0]];\n }\n n = [a * n[0] + n[1], n[0]];\n d = [a * d[0] + d[1], d[0]];\n a = Math.floor(1 / rem);\n rem = 1 / rem - a;\n }\n\n // We failed to find a nice rational representation,\n // so return an irrational \"fraction\"\n return [decimal, 1];\n}\n","// @flow\n/**\n * Vector Utils\n * A vector is an array of numbers e.g. [0, 3, 4].\n */\n\nimport _ from \"underscore\";\nimport * as knumber from \"./number.js\";\n\nfunction arraySum(array: $ReadOnlyArray<number>): number {\n return array.reduce((memo, arg) => memo + arg, 0);\n}\n\nfunction arrayProduct(array: $ReadOnlyArray<number>): number {\n return array.reduce((memo, arg) => memo * arg, 1);\n}\n\nexport function is<T>(vec: $ReadOnlyArray<T>, dimension: number): boolean {\n if (!_.isArray(vec)) {\n return false;\n }\n if (dimension !== undefined && vec.length !== dimension) {\n return false;\n }\n return vec.every(knumber.is);\n}\n\n// Normalize to a unit vector\nexport function normalize(v: $ReadOnlyArray<number>): $ReadOnlyArray<number> {\n return scale(v, 1 / length(v));\n}\n\n// Length/magnitude of a vector\nexport function length(v: $ReadOnlyArray<number>): number {\n return Math.sqrt(dot(v, v));\n}\n// Dot product of two vectors\nexport function dot(\n a: $ReadOnlyArray<number>,\n b: $ReadOnlyArray<number>,\n): number {\n // $FlowFixMe[incompatible-call] underscore doesn't like $ReadOnlyArray\n const zipped = _.zip(a, b);\n const multiplied = zipped.map(arrayProduct);\n return arraySum(multiplied);\n}\n\n/* vector-add multiple [x, y] coords/vectors\n *\n * add([1, 2], [3, 4]) -> [4, 6]\n */\nexport function add(\n ...vecs: $ReadOnlyArray<$ReadOnlyArray<number>>\n): $ReadOnlyArray<number> {\n // $FlowFixMe[incompatible-call] underscore doesn't like $ReadOnlyArray\n const zipped = _.zip(...vecs);\n return zipped.map(arraySum);\n}\n\nexport function subtract(\n v1: $ReadOnlyArray<number>,\n v2: $ReadOnlyArray<number>,\n): $ReadOnlyArray<number> {\n // $FlowFixMe[incompatible-call] underscore doesn't like $ReadOnlyArray\n return _.zip(v1, v2).map((dim) => dim[0] - dim[1]);\n}\n\nexport function negate(v: $ReadOnlyArray<number>): $ReadOnlyArray<number> {\n return v.map((x) => {\n return -x;\n });\n}\n\n// Scale a vector\nexport function scale(\n v1: $ReadOnlyArray<number>,\n scalar: number,\n): $ReadOnlyArray<number> {\n return v1.map((x) => {\n return x * scalar;\n });\n}\n\nexport function equal(\n v1: $ReadOnlyArray<number>,\n v2: $ReadOnlyArray<number>,\n tolerance?: number,\n): boolean {\n // _.zip will nicely deal with the lengths, going through\n // the length of the longest vector. knumber.equal then\n // returns false for any number compared to the undefined\n // passed in if one of the vectors is shorter.\n // $FlowFixMe[incompatible-call] underscore doesn't like $ReadOnlyArray\n return _.zip(v1, v2).every((pair) =>\n knumber.equal(pair[0], pair[1], tolerance),\n );\n}\n\nexport function codirectional(\n v1: $ReadOnlyArray<number>,\n v2: $ReadOnlyArray<number>,\n tolerance?: number,\n): boolean {\n // The origin is trivially codirectional with all other vectors.\n // This gives nice semantics for codirectionality between points when\n // comparing their difference vectors.\n if (\n knumber.equal(length(v1), 0, tolerance) ||\n knumber.equal(length(v2), 0, tolerance)\n ) {\n return true;\n }\n\n v1 = normalize(v1);\n v2 = normalize(v2);\n\n return equal(v1, v2, tolerance);\n}\n\nexport function collinear(\n v1: $ReadOnlyArray<number>,\n v2: $ReadOnlyArray<number>,\n tolerance?: number,\n): boolean {\n return (\n codirectional(v1, v2, tolerance) ||\n codirectional(v1, negate(v2), tolerance)\n );\n}\n\n// Convert a cartesian coordinate into a radian polar coordinate\nexport function polarRadFromCart(\n v: $ReadOnlyArray<number>,\n): $ReadOnlyArray<number> {\n const radius = length(v);\n let theta = Math.atan2(v[1], v[0]);\n\n // Convert angle range from [-pi, pi] to [0, 2pi]\n if (theta < 0) {\n theta += 2 * Math.PI;\n }\n\n return [radius, theta];\n}\n\n// Converts a cartesian coordinate into a degree polar coordinate\nexport function polarDegFromCart(\n v: $ReadOnlyArray<number>,\n): $ReadOnlyArray<number> /* TODO: convert to tuple/Point */ {\n const polar = polarRadFromCart(v);\n return [polar[0], (polar[1] * 180) / Math.PI];\n}\n\n/* Convert a polar coordinate into a cartesian coordinate\n *\n * Examples:\n * cartFromPolarRad(5, Math.PI)\n * cartFromPolarRad([5, Math.PI])\n */\nexport function cartFromPolarRad(\n radius: number,\n theta?: number = 0,\n): $ReadOnlyArray<number> /* TODO: convert to tuple/Point */ {\n return [radius * Math.cos(theta), radius * Math.sin(theta)];\n}\n\n/* Convert a polar coordinate into a cartesian coordinate\n *\n * Examples:\n * cartFromPolarDeg(5, 30)\n * cartFromPolarDeg([5, 30])\n */\nexport function cartFromPolarDeg(\n radius: number,\n theta?: number = 0,\n): $ReadOnlyArray<number> {\n return cartFromPolarRad(radius, (theta * Math.PI) / 180);\n}\n\n// Rotate vector\nexport function rotateRad(\n v: $ReadOnlyArray<number>,\n theta: number,\n): $ReadOnlyArray<number> {\n const polar = polarRadFromCart(v);\n const angle = polar[1] + theta;\n return cartFromPolarRad(polar[0], angle);\n}\n\nexport function rotateDeg(\n v: $ReadOnlyArray<number>,\n theta: number,\n): $ReadOnlyArray<number> {\n const polar = polarDegFromCart(v);\n const angle = polar[1] + theta;\n return cartFromPolarDeg(polar[0], angle);\n}\n\n// Angle between two vectors\nexport function angleRad(\n v1: $ReadOnlyArray<number>,\n v2: $ReadOnlyArray<number>,\n): number {\n return Math.acos(dot(v1, v2) / (length(v1) * length(v2)));\n}\n\nexport function angleDeg(\n v1: $ReadOnlyArray<number>,\n v2: $ReadOnlyArray<number>,\n): number {\n return (angleRad(v1, v2) * 180) / Math.PI;\n}\n\n// Vector projection of v1 onto v2\nexport function projection(\n v1: $ReadOnlyArray<number>,\n v2: $ReadOnlyArray<number>,\n): $ReadOnlyArray<number> {\n const scalar = dot(v1, v2) / dot(v2, v2);\n return scale(v2, scalar);\n}\n\n// Round each number to a certain number of decimal places\nexport function round(\n vec: $ReadOnlyArray<number>,\n precision: $ReadOnlyArray<number> | number,\n): $ReadOnlyArray<number> {\n return vec.map((elem, i) =>\n // $FlowFixMe[prop-missing]\n // $FlowFixMe[incompatible-call]\n knumber.round(elem, precision[i] || precision),\n );\n}\n\n// Round each number to the nearest increment\nexport function roundTo(\n vec: $ReadOnlyArray<number>,\n increment: $ReadOnlyArray<number> | number,\n): $ReadOnlyArray<number> {\n return vec.map((elem, i) =>\n // $FlowFixMe[prop-missing]\n // $FlowFixMe[incompatible-call]\n knumber.roundTo(elem, increment[i] || increment),\n );\n}\n\nexport function floorTo(\n vec: $ReadOnlyArray<number>,\n increment: $ReadOnlyArray<number> | number,\n): $ReadOnlyArray<number> {\n return vec.map((elem, i) =>\n // $FlowFixMe[prop-missing]\n // $FlowFixMe[incompatible-call]\n knumber.floorTo(elem, increment[i] || increment),\n );\n}\n\nexport function ceilTo(\n vec: $ReadOnlyArray<number>,\n increment: $ReadOnlyArray<number> | number,\n): $ReadOnlyArray<number> {\n return vec.map((elem, i) =>\n // $FlowFixMe[prop-missing]\n // $FlowFixMe[incompatible-call]\n knumber.ceilTo(elem, increment[i] || increment),\n );\n}\n","// @flow\n/**\n * Point Utils\n * A point is an array of two numbers e.g. [0, 0].\n */\n\nimport _ from \"underscore\";\n\nimport * as kvector from \"./vector.js\";\nimport * as knumber from \"./number.js\";\n\n// A point, in 2D, 3D, or nD space.\nexport type Point = $ReadOnlyArray<number>;\n\n// Rotate point (around origin unless a center is specified)\nexport function rotateRad(point: Point, theta: number, center: Point): Point {\n if (center === undefined) {\n return kvector.rotateRad(point, theta);\n } else {\n return kvector.add(\n center,\n kvector.rotateRad(kvector.subtract(point, center), theta),\n );\n }\n}\n\nexport function rotateDeg(point: Point, theta: number, center: Point): Point {\n if (center === undefined) {\n return kvector.rotateDeg(point, theta);\n } else {\n return kvector.add(\n center,\n kvector.rotateDeg(kvector.subtract(point, center), theta),\n );\n }\n}\n\n// Distance between two points\nexport function distanceToPoint(point1: Point, point2: Point): number {\n return kvector.length(kvector.subtract(point1, point2));\n}\n\n// Distance between point and line\nexport function distanceToLine(point: Point, line: [Point, Point]): number {\n const lv = kvector.subtract(line[1], line[0]);\n const pv = kvector.subtract(point, line[0]);\n const projectedPv = kvector.projection(pv, lv);\n const distancePv = kvector.subtract(projectedPv, pv);\n return kvector.length(distancePv);\n}\n\n// Reflect point over line\nexport function reflectOverLine(\n point: Point,\n line: [Point, Point],\n): $ReadOnlyArray<number> /* TODO: convert to Point */ {\n const lv = kvector.subtract(line[1], line[0]);\n const pv = kvector.subtract(point, line[0]);\n const projectedPv = kvector.projection(pv, lv);\n const reflectedPv = kvector.subtract(kvector.scale(projectedPv, 2), pv);\n return kvector.add(line[0], reflectedPv);\n}\n\n/**\n * Compares two points, returning -1, 0, or 1, for use with\n * Array.prototype.sort\n *\n * Note: This technically doesn't satisfy the total-ordering\n * requirements of Array.prototype.sort unless equalityTolerance\n * is 0. In some cases very close points that compare within a\n * few equalityTolerances could appear in the wrong order.\n */\nexport function compare(\n point1: Point,\n point2: Point,\n equalityTolerance?: number,\n): number /* TODO: convert to -1 | 0 | 1 type */ {\n if (point1.length !== point2.length) {\n return point1.length - point2.length;\n }\n for (let i = 0; i < point1.length; i++) {\n if (!knumber.equal(point1[i], point2[i], equalityTolerance)) {\n return point1[i] - point2[i];\n }\n }\n return 0;\n}\n\n// Check if a value is a point\nexport const is = kvector.is;\n\n// Add and subtract vector(s)\nexport const addVector = kvector.add;\nexport const addVectors = kvector.add;\nexport const subtractVector = kvector.subtract;\nexport const equal = kvector.equal;\n\n// Convert from cartesian to polar and back\nexport const polarRadFromCart = kvector.polarRadFromCart;\nexport const polarDegFromCart = kvector.polarDegFromCart;\nexport const cartFromPolarRad = kvector.cartFromPolarRad;\nexport const cartFromPolarDeg = kvector.cartFromPolarDeg;\n\n// Rounding\nexport const round = kvector.round;\nexport const roundTo = kvector.roundTo;\nexport const floorTo = kvector.floorTo;\nexport const ceilTo = kvector.ceilTo;\n","// @flow\n/**\n * Line Utils\n * A line is an array of two points e.g. [[-5, 0], [5, 0]].\n */\n\nimport * as kpoint from \"./point.js\";\nimport * as kvector from \"./vector.js\";\n\nimport type {Point} from \"./point.js\";\n\nexport type Line = [Point, Point];\n\nexport function distanceToPoint(line: Line, point: Point): number {\n return kpoint.distanceToLine(point, line);\n}\n\nexport function reflectPoint(\n line: Line,\n point: Point,\n): $ReadOnlyArray<number> /* TODO: convert to Point */ {\n return kpoint.reflectOverLine(point, line);\n}\n\nexport function midpoint(line: Line): Point {\n return [(line[0][0] + line[1][0]) / 2, (line[0][1] + line[1][1]) / 2];\n}\n\nexport function equal(line1: Line, line2: Line, tolerance?: number): boolean {\n // TODO: A nicer implementation might just check collinearity of\n // vectors using underscore magick\n // Compare the directions of the lines\n const v1 = kvector.subtract(line1[1], line1[0]);\n const v2 = kvector.subtract(line2[1], line2[0]);\n if (!kvector.collinear(v1, v2, tolerance)) {\n return false;\n }\n // If the start point is the same for the two lines, then they are the same\n if (kpoint.equal(line1[0], line2[0])) {\n return true;\n }\n // Make sure that the direction to get from line1 to\n // line2 is the same as the direction of the lines\n const line1ToLine2Vector = kvector.subtract(line2[0], line1[0]);\n return kvector.collinear(v1, line1ToLine2Vector, tolerance);\n}\n","// @flow\n/**\n * Ray Utils\n * A ray (→) is an array of an endpoint and another point along the ray.\n * For example, [[0, 0], [1, 0]] is the ray starting at the origin and\n * traveling along the positive x-axis.\n */\n\nimport * as kvector from \"./vector.js\";\nimport * as kpoint from \"./point.js\";\n\nimport type {Point} from \"./point\";\n\nexport type Ray = [Point, Point];\n\nexport function equal(ray1: Ray, ray2: Ray, tolerance: number): boolean {\n // Compare the directions of the rays\n const v1 = kvector.subtract(ray1[1], ray1[0]);\n const v2 = kvector.subtract(ray2[1], ray2[0]);\n\n const sameOrigin = kpoint.equal(ray1[0], ray2[0]);\n const codirectional = kvector.codirectional(v1, v2, tolerance);\n\n return sameOrigin && codirectional;\n}\n"],"names":["EPSILON","Math","pow","is","x","_","isNumber","isNaN","equal","y","tolerance","abs","round","num","precision","factor","roundTo","increment","floorTo","floor","ceilTo","ceil","decimal","maxDenominator","n","d","a","rem","arraySum","array","reduce","memo","arg","arrayProduct","vec","dimension","isArray","undefined","length","every","knumber","normalize","v","scale","sqrt","dot","b","zip","map","add","zipped","subtract","v1","v2","dim","negate","scalar","pair","codirectional","collinear","polarRadFromCart","radius","theta","atan2","PI","polarDegFromCart","polar","cartFromPolarRad","cos","sin","cartFromPolarDeg","rotateRad","angle","rotateDeg","angleRad","acos","projection","elem","i","distanceToLine","point","line","lv","kvector","pv","reflectOverLine","reflectedPv","addVector","addVectors","subtractVector","center","point1","point2","equalityTolerance","kpoint","line1","line2","ray1","ray2","sameOrigin"],"mappings":"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"}
|
|
Binary file
|
package/logo.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="400" height="400" viewBox="0 0 400 400"><defs/><ellipse cx="200" cy="200" rx="200" ry="200" fill="#28ae7b" stroke="none" style="stroke-width: 2px" stroke-width="2"/><path fill="#ffffff" stroke="#ffffff" d="M 293.05,242.4 C 295.7,226.5 324.85,202.65 332.8,200 C 324.85,197.35 295.7,173.5 293.05,157.6" transform="" style="stroke-width: 25px;stroke-linejoin: round;stroke-linecap: round" stroke-width="25" stroke-linejoin="round" stroke-linecap="round"/><path fill="#ffffff" stroke="#ffffff" d="M 80,200 S 80,200 332.05,200" style="stroke-width: 25px" stroke-width="25"/><path fill="#ffffff" stroke="#ffffff" d="M 200,320 L 200,80" style="stroke-width: 25px" stroke-width="25"/></svg>
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"publishConfig": {
|
|
3
|
+
"access": "public"
|
|
4
|
+
},
|
|
5
|
+
"name": "@khanacademy/kmath",
|
|
6
|
+
"version": "0.0.3",
|
|
7
|
+
"description": "Khan Academy's Javascript Numeric Math Utilities",
|
|
8
|
+
"module": "dist/es/index.js",
|
|
9
|
+
"main": "dist/index.js",
|
|
10
|
+
"source": "src/index.js",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"test": "bash -c 'yarn --silent --cwd \"../..\" test ${@:0} $($([[ ${@: -1} = -* ]] || [[ ${@: -1} = bash ]]) && echo $PWD)'"
|
|
13
|
+
},
|
|
14
|
+
"dependencies": {},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"perseus-build-settings": "^0.0.1",
|
|
17
|
+
"underscore": "1.4.4"
|
|
18
|
+
},
|
|
19
|
+
"peerDependencies": {
|
|
20
|
+
"underscore": "1.4.4"
|
|
21
|
+
},
|
|
22
|
+
"author": "Khan Academy",
|
|
23
|
+
"license": "MIT"
|
|
24
|
+
}
|