@khanacademy/kmath 0.0.4 → 0.0.6
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/CHANGELOG.md +12 -0
- package/README.md +124 -85
- package/dist/es/index.js +499 -1
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +511 -1
- package/dist/index.js.map +1 -1
- package/package.json +14 -6
- package/src/line.js +1 -4
- package/src/logo.js +5 -3
- package/src/point.js +4 -7
- package/src/ray.js +2 -2
- package/src/vector.js +38 -61
package/package.json
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
{
|
|
2
|
+
"name": "@khanacademy/kmath",
|
|
3
|
+
"description": "Khan Academy's Javascript Numeric Math Utilities",
|
|
4
|
+
"author": "Khan Academy",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"version": "0.0.6",
|
|
2
7
|
"publishConfig": {
|
|
3
8
|
"access": "public"
|
|
4
9
|
},
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/Khan/kmath.git"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/Khan/perseus/issues"
|
|
16
|
+
},
|
|
8
17
|
"module": "dist/es/index.js",
|
|
9
18
|
"main": "dist/index.js",
|
|
10
19
|
"source": "src/index.js",
|
|
@@ -13,12 +22,11 @@
|
|
|
13
22
|
},
|
|
14
23
|
"dependencies": {},
|
|
15
24
|
"devDependencies": {
|
|
16
|
-
"perseus-build-settings": "^0.0.
|
|
25
|
+
"perseus-build-settings": "^0.0.3",
|
|
17
26
|
"underscore": "1.4.4"
|
|
18
27
|
},
|
|
19
28
|
"peerDependencies": {
|
|
20
29
|
"underscore": "1.4.4"
|
|
21
30
|
},
|
|
22
|
-
"
|
|
23
|
-
"license": "MIT"
|
|
31
|
+
"keywords": []
|
|
24
32
|
}
|
package/src/line.js
CHANGED
|
@@ -15,10 +15,7 @@ export function distanceToPoint(line: Line, point: Point): number {
|
|
|
15
15
|
return kpoint.distanceToLine(point, line);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export function reflectPoint(
|
|
19
|
-
line: Line,
|
|
20
|
-
point: Point,
|
|
21
|
-
): $ReadOnlyArray<number> /* TODO: convert to Point */ {
|
|
18
|
+
export function reflectPoint(line: Line, point: Point): Point {
|
|
22
19
|
return kpoint.reflectOverLine(point, line);
|
|
23
20
|
}
|
|
24
21
|
|
package/src/logo.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
+
/* eslint-disable import/no-default-export */
|
|
2
|
+
// @flow
|
|
1
3
|
// This file describes the graphie source code of the kmath logo
|
|
2
4
|
// currently used on khan.github.io.
|
|
3
5
|
//
|
|
4
6
|
// Also located at http://ka-perseus-graphie.s3.amazonaws.com/42ef3cbadc3e6464124533191728c3c5c55c7355.svg
|
|
5
7
|
|
|
6
|
-
// eslint-disable-next-line
|
|
8
|
+
// eslint-disable-next-line ft-flow/no-types-missing-file-annotation
|
|
7
9
|
declare var init: $FlowFixMe;
|
|
8
|
-
// eslint-disable-next-line
|
|
10
|
+
// eslint-disable-next-line ft-flow/no-types-missing-file-annotation
|
|
9
11
|
declare var ellipse: $FlowFixMe;
|
|
10
|
-
// eslint-disable-next-line
|
|
12
|
+
// eslint-disable-next-line ft-flow/no-types-missing-file-annotation
|
|
11
13
|
declare var line: $FlowFixMe;
|
|
12
14
|
|
|
13
15
|
const GREEN = "#28AE7B";
|
package/src/point.js
CHANGED
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
|
|
7
7
|
import _ from "underscore";
|
|
8
8
|
|
|
9
|
-
import * as kvector from "./vector.js";
|
|
10
9
|
import * as knumber from "./number.js";
|
|
10
|
+
import * as kvector from "./vector.js";
|
|
11
11
|
|
|
12
12
|
// A point, in 2D, 3D, or nD space.
|
|
13
13
|
export type Point = $ReadOnlyArray<number>;
|
|
14
14
|
|
|
15
15
|
// Rotate point (around origin unless a center is specified)
|
|
16
|
-
export function rotateRad(point: Point, theta: number, center
|
|
16
|
+
export function rotateRad(point: Point, theta: number, center?: Point): Point {
|
|
17
17
|
if (center === undefined) {
|
|
18
18
|
return kvector.rotateRad(point, theta);
|
|
19
19
|
} else {
|
|
@@ -24,7 +24,7 @@ export function rotateRad(point: Point, theta: number, center: Point): Point {
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export function rotateDeg(point: Point, theta: number, center
|
|
27
|
+
export function rotateDeg(point: Point, theta: number, center?: Point): Point {
|
|
28
28
|
if (center === undefined) {
|
|
29
29
|
return kvector.rotateDeg(point, theta);
|
|
30
30
|
} else {
|
|
@@ -50,10 +50,7 @@ export function distanceToLine(point: Point, line: [Point, Point]): number {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
// Reflect point over line
|
|
53
|
-
export function reflectOverLine(
|
|
54
|
-
point: Point,
|
|
55
|
-
line: [Point, Point],
|
|
56
|
-
): $ReadOnlyArray<number> /* TODO: convert to Point */ {
|
|
53
|
+
export function reflectOverLine<P: Point>(point: P, line: [P, P]): P {
|
|
57
54
|
const lv = kvector.subtract(line[1], line[0]);
|
|
58
55
|
const pv = kvector.subtract(point, line[0]);
|
|
59
56
|
const projectedPv = kvector.projection(pv, lv);
|
package/src/ray.js
CHANGED
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
* traveling along the positive x-axis.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import * as kvector from "./vector.js";
|
|
10
9
|
import * as kpoint from "./point.js";
|
|
10
|
+
import * as kvector from "./vector.js";
|
|
11
11
|
|
|
12
12
|
import type {Point} from "./point";
|
|
13
13
|
|
|
14
14
|
export type Ray = [Point, Point];
|
|
15
15
|
|
|
16
|
-
export function equal(ray1: Ray, ray2: Ray, tolerance
|
|
16
|
+
export function equal(ray1: Ray, ray2: Ray, tolerance?: number): boolean {
|
|
17
17
|
// Compare the directions of the rays
|
|
18
18
|
const v1 = kvector.subtract(ray1[1], ray1[0]);
|
|
19
19
|
const v2 = kvector.subtract(ray2[1], ray2[0]);
|
package/src/vector.js
CHANGED
|
@@ -5,8 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import _ from "underscore";
|
|
8
|
+
|
|
8
9
|
import * as knumber from "./number.js";
|
|
9
10
|
|
|
11
|
+
type Vector = $ReadOnlyArray<number>;
|
|
12
|
+
|
|
10
13
|
function arraySum(array: $ReadOnlyArray<number>): number {
|
|
11
14
|
return array.reduce((memo, arg) => memo + arg, 0);
|
|
12
15
|
}
|
|
@@ -15,7 +18,15 @@ function arrayProduct(array: $ReadOnlyArray<number>): number {
|
|
|
15
18
|
return array.reduce((memo, arg) => memo * arg, 1);
|
|
16
19
|
}
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Checks if the given vector contains only numbers and, optionally, is of the
|
|
23
|
+
* right dimension (length).
|
|
24
|
+
*
|
|
25
|
+
* is([1, 2, 3]) -> true
|
|
26
|
+
* is([1, "Hello", 3]) -> false
|
|
27
|
+
* is([1, 2, 3], 1) -> false
|
|
28
|
+
*/
|
|
29
|
+
export function is<T>(vec: $ReadOnlyArray<T>, dimension?: number): boolean {
|
|
19
30
|
if (!_.isArray(vec)) {
|
|
20
31
|
return false;
|
|
21
32
|
}
|
|
@@ -26,19 +37,16 @@ export function is<T>(vec: $ReadOnlyArray<T>, dimension: number): boolean {
|
|
|
26
37
|
}
|
|
27
38
|
|
|
28
39
|
// Normalize to a unit vector
|
|
29
|
-
export function normalize(v:
|
|
40
|
+
export function normalize<V: Vector>(v: V): V {
|
|
30
41
|
return scale(v, 1 / length(v));
|
|
31
42
|
}
|
|
32
43
|
|
|
33
44
|
// Length/magnitude of a vector
|
|
34
|
-
export function length(v:
|
|
45
|
+
export function length(v: Vector): number {
|
|
35
46
|
return Math.sqrt(dot(v, v));
|
|
36
47
|
}
|
|
37
48
|
// Dot product of two vectors
|
|
38
|
-
export function dot(
|
|
39
|
-
a: $ReadOnlyArray<number>,
|
|
40
|
-
b: $ReadOnlyArray<number>,
|
|
41
|
-
): number {
|
|
49
|
+
export function dot(a: Vector, b: Vector): number {
|
|
42
50
|
// $FlowFixMe[incompatible-call] underscore doesn't like $ReadOnlyArray
|
|
43
51
|
const zipped = _.zip(a, b);
|
|
44
52
|
const multiplied = zipped.map(arrayProduct);
|
|
@@ -49,43 +57,33 @@ export function dot(
|
|
|
49
57
|
*
|
|
50
58
|
* add([1, 2], [3, 4]) -> [4, 6]
|
|
51
59
|
*/
|
|
52
|
-
export function add(
|
|
53
|
-
...vecs: $ReadOnlyArray<$ReadOnlyArray<number>>
|
|
54
|
-
): $ReadOnlyArray<number> {
|
|
60
|
+
export function add<V: Vector>(...vecs: $ReadOnlyArray<V>): V {
|
|
55
61
|
// $FlowFixMe[incompatible-call] underscore doesn't like $ReadOnlyArray
|
|
56
62
|
const zipped = _.zip(...vecs);
|
|
57
63
|
return zipped.map(arraySum);
|
|
58
64
|
}
|
|
59
65
|
|
|
60
|
-
export function subtract(
|
|
61
|
-
v1: $ReadOnlyArray<number>,
|
|
62
|
-
v2: $ReadOnlyArray<number>,
|
|
63
|
-
): $ReadOnlyArray<number> {
|
|
66
|
+
export function subtract<V: Vector>(v1: V, v2: V): V {
|
|
64
67
|
// $FlowFixMe[incompatible-call] underscore doesn't like $ReadOnlyArray
|
|
65
68
|
return _.zip(v1, v2).map((dim) => dim[0] - dim[1]);
|
|
66
69
|
}
|
|
67
70
|
|
|
68
|
-
export function negate(v:
|
|
71
|
+
export function negate<V: Vector>(v: V): V {
|
|
72
|
+
// $FlowFixMe[incompatible-return] Flow's `.map()` libdef is lacking
|
|
69
73
|
return v.map((x) => {
|
|
70
74
|
return -x;
|
|
71
75
|
});
|
|
72
76
|
}
|
|
73
77
|
|
|
74
78
|
// Scale a vector
|
|
75
|
-
export function scale(
|
|
76
|
-
|
|
77
|
-
scalar: number,
|
|
78
|
-
): $ReadOnlyArray<number> {
|
|
79
|
+
export function scale<V: Vector>(v1: V, scalar: number): V {
|
|
80
|
+
// $FlowFixMe[incompatible-return] Flow's `.map()` libdef is lacking
|
|
79
81
|
return v1.map((x) => {
|
|
80
82
|
return x * scalar;
|
|
81
83
|
});
|
|
82
84
|
}
|
|
83
85
|
|
|
84
|
-
export function equal(
|
|
85
|
-
v1: $ReadOnlyArray<number>,
|
|
86
|
-
v2: $ReadOnlyArray<number>,
|
|
87
|
-
tolerance?: number,
|
|
88
|
-
): boolean {
|
|
86
|
+
export function equal(v1: Vector, v2: Vector, tolerance?: number): boolean {
|
|
89
87
|
// _.zip will nicely deal with the lengths, going through
|
|
90
88
|
// the length of the longest vector. knumber.equal then
|
|
91
89
|
// returns false for any number compared to the undefined
|
|
@@ -97,8 +95,8 @@ export function equal(
|
|
|
97
95
|
}
|
|
98
96
|
|
|
99
97
|
export function codirectional(
|
|
100
|
-
v1:
|
|
101
|
-
v2:
|
|
98
|
+
v1: Vector,
|
|
99
|
+
v2: Vector,
|
|
102
100
|
tolerance?: number,
|
|
103
101
|
): boolean {
|
|
104
102
|
// The origin is trivially codirectional with all other vectors.
|
|
@@ -117,17 +115,15 @@ export function codirectional(
|
|
|
117
115
|
return equal(v1, v2, tolerance);
|
|
118
116
|
}
|
|
119
117
|
|
|
120
|
-
export function collinear(
|
|
121
|
-
v1: $ReadOnlyArray<number>,
|
|
122
|
-
v2: $ReadOnlyArray<number>,
|
|
123
|
-
tolerance?: number,
|
|
124
|
-
): boolean {
|
|
118
|
+
export function collinear(v1: Vector, v2: Vector, tolerance?: number): boolean {
|
|
125
119
|
return (
|
|
126
120
|
codirectional(v1, v2, tolerance) ||
|
|
127
121
|
codirectional(v1, negate(v2), tolerance)
|
|
128
122
|
);
|
|
129
123
|
}
|
|
130
124
|
|
|
125
|
+
// TODO(jeremy) These coordinate conversion functions really only handle 2D points (ie. [number, number])
|
|
126
|
+
|
|
131
127
|
// Convert a cartesian coordinate into a radian polar coordinate
|
|
132
128
|
export function polarRadFromCart(
|
|
133
129
|
v: $ReadOnlyArray<number>,
|
|
@@ -155,7 +151,6 @@ export function polarDegFromCart(
|
|
|
155
151
|
*
|
|
156
152
|
* Examples:
|
|
157
153
|
* cartFromPolarRad(5, Math.PI)
|
|
158
|
-
* cartFromPolarRad([5, Math.PI])
|
|
159
154
|
*/
|
|
160
155
|
export function cartFromPolarRad(
|
|
161
156
|
radius: number,
|
|
@@ -168,7 +163,6 @@ export function cartFromPolarRad(
|
|
|
168
163
|
*
|
|
169
164
|
* Examples:
|
|
170
165
|
* cartFromPolarDeg(5, 30)
|
|
171
|
-
* cartFromPolarDeg([5, 30])
|
|
172
166
|
*/
|
|
173
167
|
export function cartFromPolarDeg(
|
|
174
168
|
radius: number,
|
|
@@ -197,34 +191,23 @@ export function rotateDeg(
|
|
|
197
191
|
}
|
|
198
192
|
|
|
199
193
|
// Angle between two vectors
|
|
200
|
-
export function angleRad(
|
|
201
|
-
v1: $ReadOnlyArray<number>,
|
|
202
|
-
v2: $ReadOnlyArray<number>,
|
|
203
|
-
): number {
|
|
194
|
+
export function angleRad(v1: Vector, v2: Vector): number {
|
|
204
195
|
return Math.acos(dot(v1, v2) / (length(v1) * length(v2)));
|
|
205
196
|
}
|
|
206
197
|
|
|
207
|
-
export function angleDeg(
|
|
208
|
-
v1: $ReadOnlyArray<number>,
|
|
209
|
-
v2: $ReadOnlyArray<number>,
|
|
210
|
-
): number {
|
|
198
|
+
export function angleDeg(v1: Vector, v2: Vector): number {
|
|
211
199
|
return (angleRad(v1, v2) * 180) / Math.PI;
|
|
212
200
|
}
|
|
213
201
|
|
|
214
202
|
// Vector projection of v1 onto v2
|
|
215
|
-
export function projection(
|
|
216
|
-
v1: $ReadOnlyArray<number>,
|
|
217
|
-
v2: $ReadOnlyArray<number>,
|
|
218
|
-
): $ReadOnlyArray<number> {
|
|
203
|
+
export function projection<V: Vector>(v1: V, v2: V): V {
|
|
219
204
|
const scalar = dot(v1, v2) / dot(v2, v2);
|
|
220
205
|
return scale(v2, scalar);
|
|
221
206
|
}
|
|
222
207
|
|
|
223
208
|
// Round each number to a certain number of decimal places
|
|
224
|
-
export function round(
|
|
225
|
-
|
|
226
|
-
precision: $ReadOnlyArray<number> | number,
|
|
227
|
-
): $ReadOnlyArray<number> {
|
|
209
|
+
export function round<V: Vector>(vec: V, precision: V | number): V {
|
|
210
|
+
// $FlowFixMe[incompatible-return] Flow's `.map()` libdef is lacking
|
|
228
211
|
return vec.map((elem, i) =>
|
|
229
212
|
// $FlowFixMe[prop-missing]
|
|
230
213
|
// $FlowFixMe[incompatible-call]
|
|
@@ -233,10 +216,8 @@ export function round(
|
|
|
233
216
|
}
|
|
234
217
|
|
|
235
218
|
// Round each number to the nearest increment
|
|
236
|
-
export function roundTo(
|
|
237
|
-
|
|
238
|
-
increment: $ReadOnlyArray<number> | number,
|
|
239
|
-
): $ReadOnlyArray<number> {
|
|
219
|
+
export function roundTo<V: Vector>(vec: V, increment: V | number): V {
|
|
220
|
+
// $FlowFixMe[incompatible-return] Flow's `.map()` libdef is lacking
|
|
240
221
|
return vec.map((elem, i) =>
|
|
241
222
|
// $FlowFixMe[prop-missing]
|
|
242
223
|
// $FlowFixMe[incompatible-call]
|
|
@@ -244,10 +225,8 @@ export function roundTo(
|
|
|
244
225
|
);
|
|
245
226
|
}
|
|
246
227
|
|
|
247
|
-
export function floorTo(
|
|
248
|
-
|
|
249
|
-
increment: $ReadOnlyArray<number> | number,
|
|
250
|
-
): $ReadOnlyArray<number> {
|
|
228
|
+
export function floorTo<V: Vector>(vec: V, increment: V | number): V {
|
|
229
|
+
// $FlowFixMe[incompatible-return] Flow's `.map()` libdef is lacking
|
|
251
230
|
return vec.map((elem, i) =>
|
|
252
231
|
// $FlowFixMe[prop-missing]
|
|
253
232
|
// $FlowFixMe[incompatible-call]
|
|
@@ -255,10 +234,8 @@ export function floorTo(
|
|
|
255
234
|
);
|
|
256
235
|
}
|
|
257
236
|
|
|
258
|
-
export function ceilTo(
|
|
259
|
-
|
|
260
|
-
increment: $ReadOnlyArray<number> | number,
|
|
261
|
-
): $ReadOnlyArray<number> {
|
|
237
|
+
export function ceilTo<V: Vector>(vec: V, increment: V | number): V {
|
|
238
|
+
// $FlowFixMe[incompatible-return] Flow's `.map()` libdef is lacking
|
|
262
239
|
return vec.map((elem, i) =>
|
|
263
240
|
// $FlowFixMe[prop-missing]
|
|
264
241
|
// $FlowFixMe[incompatible-call]
|