@khanacademy/kmath 0.2.0 → 0.3.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.
@@ -0,0 +1,29 @@
1
+ /**
2
+ * A collection of geomtry-related utility functions
3
+ */
4
+ import { type Coord } from "@khanacademy/perseus-core";
5
+ type Line = [Coord, Coord];
6
+ export type Range = [number, number];
7
+ export type SineCoefficient = [
8
+ number,
9
+ number,
10
+ number,
11
+ number
12
+ ];
13
+ export declare function sign(val: number): 0 | 1 | -1;
14
+ export declare function ccw(a: Coord, b: Coord, c: Coord): number;
15
+ export declare function collinear(a: Coord, b: Coord, c: Coord): boolean;
16
+ export declare function intersects(ab: Line, cd: Line): boolean;
17
+ export declare function polygonSidesIntersect(vertices: Coord[]): boolean;
18
+ export declare function vector(a: any, b: any): number[];
19
+ export declare function reverseVector(vector: Coord): Coord;
20
+ export declare function clockwise(points: Coord[]): boolean;
21
+ export declare function magnitude(v: ReadonlyArray<Coord>): number;
22
+ export declare function angleMeasures(coords: ReadonlyArray<Coord>): ReadonlyArray<number>;
23
+ export declare function similar(coords1: ReadonlyArray<Coord>, coords2: ReadonlyArray<Coord>, tolerance: number): boolean;
24
+ export declare function lawOfCosines(a: number, b: number, c: number): number;
25
+ export declare function canonicalSineCoefficients([amplitude, angularFrequency, phase, verticalOffset,]: [any, any, any, any]): any[];
26
+ export declare function rotate<T>(array: ReadonlyArray<T>, n?: number): ReadonlyArray<T>;
27
+ export declare function getLineEquation(first: Coord, second: Coord): string;
28
+ export declare function getLineIntersection(firstPoints: ReadonlyArray<Coord>, secondPoints: ReadonlyArray<Coord>): string;
29
+ export {};
package/dist/index.d.ts CHANGED
@@ -4,4 +4,10 @@ export * as vector from "./vector";
4
4
  export * as point from "./point";
5
5
  export * as line from "./line";
6
6
  export * as ray from "./ray";
7
+ export * as angles from "./angles";
8
+ export * as geometry from "./geometry";
9
+ export * as coefficients from "./coefficients";
7
10
  export { default as KhanMath, sum } from "./math";
11
+ export type { Range, SineCoefficient } from "./geometry";
12
+ export type { NamedSineCoefficient, QuadraticCoefficient } from "./coefficients";
13
+ export type * from "./types";
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ var ___default = /*#__PURE__*/_interopDefaultLegacy(_);
12
12
 
13
13
  // This file is processed by a Rollup plugin (replace) to inject the production
14
14
  const libName = "@khanacademy/kmath";
15
- const libVersion = "0.2.0";
15
+ const libVersion = "0.3.1";
16
16
  perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
17
17
 
18
18
  /**
@@ -41,7 +41,7 @@ function equal$4(x, y, tolerance) {
41
41
  }
42
42
  return Math.abs(x - y) < tolerance;
43
43
  }
44
- function sign(x, tolerance) /* Should be: 0 | 1 | -1 */{
44
+ function sign$1(x, tolerance) /* Should be: 0 | 1 | -1 */{
45
45
  return equal$4(x, 0, tolerance) ? 0 : Math.abs(x) / x;
46
46
  }
47
47
  function isInteger(num, tolerance) {
@@ -110,7 +110,7 @@ var number = /*#__PURE__*/Object.freeze({
110
110
  EPSILON: EPSILON,
111
111
  is: is$2,
112
112
  equal: equal$4,
113
- sign: sign,
113
+ sign: sign$1,
114
114
  isInteger: isInteger,
115
115
  round: round$2,
116
116
  roundTo: roundTo$2,
@@ -220,7 +220,7 @@ function codirectional(v1, v2, tolerance) {
220
220
  v2 = normalize(v2);
221
221
  return equal$3(v1, v2, tolerance);
222
222
  }
223
- function collinear(v1, v2, tolerance) {
223
+ function collinear$1(v1, v2, tolerance) {
224
224
  return codirectional(v1, v2, tolerance) || codirectional(v1, negate(v2), tolerance);
225
225
  }
226
226
 
@@ -311,7 +311,7 @@ function ceilTo$1(vec, increment) {
311
311
  return vec.map((elem, i) => ceilTo$2(elem, increment[i] || increment));
312
312
  }
313
313
 
314
- var vector = /*#__PURE__*/Object.freeze({
314
+ var vector$1 = /*#__PURE__*/Object.freeze({
315
315
  __proto__: null,
316
316
  zip: zip,
317
317
  map: map,
@@ -325,7 +325,7 @@ var vector = /*#__PURE__*/Object.freeze({
325
325
  scale: scale,
326
326
  equal: equal$3,
327
327
  codirectional: codirectional,
328
- collinear: collinear,
328
+ collinear: collinear$1,
329
329
  polarRadFromCart: polarRadFromCart$1,
330
330
  polarDegFromCart: polarDegFromCart$1,
331
331
  cartFromPolarRad: cartFromPolarRad$1,
@@ -471,7 +471,7 @@ function equal$1(line1, line2, tolerance) {
471
471
  // Compare the directions of the lines
472
472
  const v1 = subtract(line1[1], line1[0]);
473
473
  const v2 = subtract(line2[1], line2[0]);
474
- if (!collinear(v1, v2, tolerance)) {
474
+ if (!collinear$1(v1, v2, tolerance)) {
475
475
  return false;
476
476
  }
477
477
  // If the start point is the same for the two lines, then they are the same
@@ -481,7 +481,7 @@ function equal$1(line1, line2, tolerance) {
481
481
  // Make sure that the direction to get from line1 to
482
482
  // line2 is the same as the direction of the lines
483
483
  const line1ToLine2Vector = subtract(line2[0], line1[0]);
484
- return collinear(v1, line1ToLine2Vector, tolerance);
484
+ return collinear$1(v1, line1ToLine2Vector, tolerance);
485
485
  }
486
486
 
487
487
  var line = /*#__PURE__*/Object.freeze({
@@ -512,6 +512,377 @@ var ray = /*#__PURE__*/Object.freeze({
512
512
  equal: equal
513
513
  });
514
514
 
515
+ /**
516
+ * A collection of geomtry-related utility functions
517
+ */
518
+
519
+ // This should really be a readonly tuple of [number, number]
520
+
521
+ // Given a number, return whether it is positive (1), negative (-1), or zero (0)
522
+ function sign(val) {
523
+ if (perseusCore.approximateEqual(val, 0)) {
524
+ return 0;
525
+ }
526
+ return val > 0 ? 1 : -1;
527
+ }
528
+
529
+ // Determine whether three points are collinear (0), for a clockwise turn (negative),
530
+ // or counterclockwise turn (positive)
531
+ function ccw(a, b, c) {
532
+ return (b[0] - a[0]) * (c[1] - a[1]) - (c[0] - a[0]) * (b[1] - a[1]);
533
+ }
534
+ function collinear(a, b, c) {
535
+ return perseusCore.approximateEqual(ccw(a, b, c), 0);
536
+ }
537
+
538
+ // Given rect bounding points A and B, whether point C is inside the rect
539
+ function pointInRect(a, b, c) {
540
+ return c[0] <= Math.max(a[0], b[0]) && c[0] >= Math.min(a[0], b[0]) && c[1] <= Math.max(a[1], b[1]) && c[1] >= Math.min(a[1], b[1]);
541
+ }
542
+
543
+ // Whether line segment AB intersects line segment CD
544
+ // http://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/
545
+ function intersects(ab, cd) {
546
+ const triplets = [[ab[0], ab[1], cd[0]], [ab[0], ab[1], cd[1]], [cd[0], cd[1], ab[0]], [cd[0], cd[1], ab[1]]];
547
+ const orientations = ___default["default"].map(triplets, function (triplet) {
548
+ return sign(ccw(...triplet));
549
+ });
550
+ if (orientations[0] !== orientations[1] && orientations[2] !== orientations[3]) {
551
+ return true;
552
+ }
553
+ for (let i = 0; i < 4; i++) {
554
+ if (orientations[i] === 0 && pointInRect(...triplets[i])) {
555
+ return true;
556
+ }
557
+ }
558
+ return false;
559
+ }
560
+
561
+ // Whether any two sides of a polygon intersect each other
562
+ function polygonSidesIntersect(vertices) {
563
+ for (let i = 0; i < vertices.length; i++) {
564
+ for (let k = i + 1; k < vertices.length; k++) {
565
+ // If any two vertices are the same point, sides overlap
566
+ if (kmath.point.equal(vertices[i], vertices[k])) {
567
+ return true;
568
+ }
569
+
570
+ // Find the other end of the sides starting at vertices i and k
571
+ const iNext = (i + 1) % vertices.length;
572
+ const kNext = (k + 1) % vertices.length;
573
+
574
+ // Adjacent sides always intersect (at the vertex); skip those
575
+ if (iNext === k || kNext === i) {
576
+ continue;
577
+ }
578
+ const side1 = [vertices[i], vertices[iNext]];
579
+ const side2 = [vertices[k], vertices[kNext]];
580
+ if (intersects(side1, side2)) {
581
+ return true;
582
+ }
583
+ }
584
+ }
585
+ return false;
586
+ }
587
+ function vector(a, b) {
588
+ return ___default["default"].map(___default["default"].zip(a, b), function (pair) {
589
+ return pair[0] - pair[1];
590
+ });
591
+ }
592
+ function reverseVector(vector) {
593
+ return [-vector[0], -vector[1]];
594
+ }
595
+
596
+ // Returns whether connecting the given sequence of `points` forms a clockwise
597
+ // path (assuming a closed loop, where the last point connects back to the
598
+ // first).
599
+ function clockwise(points) {
600
+ const segments = ___default["default"].zip(points, points.slice(1).concat(points.slice(0, 1)));
601
+ const areas = ___default["default"].map(segments, function (segment) {
602
+ const p1 = segment[0];
603
+ const p2 = segment[1];
604
+ return (p2[0] - p1[0]) * (p2[1] + p1[1]);
605
+ });
606
+ return kmath.sum(areas) > 0;
607
+ }
608
+ function magnitude(v) {
609
+ return Math.sqrt(___default["default"].reduce(v, function (memo, el) {
610
+ // @ts-expect-error - TS2345 - Argument of type 'Coord' is not assignable to parameter of type 'number'.
611
+ return memo + Math.pow(el, 2);
612
+ }, 0));
613
+ }
614
+ function dotProduct(a, b) {
615
+ return ___default["default"].reduce(___default["default"].zip(a, b), function (memo, pair) {
616
+ return memo + pair[0] * pair[1];
617
+ }, 0);
618
+ }
619
+ function sideLengths(coords) {
620
+ const segments = ___default["default"].zip(coords, rotate(coords));
621
+ return segments.map(function (segment) {
622
+ // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'readonly Coord[]'. | TS2556 - A spread argument must either have a tuple type or be passed to a rest parameter.
623
+ return magnitude(vector(...segment));
624
+ });
625
+ }
626
+
627
+ // Based on http://math.stackexchange.com/a/151149
628
+ function angleMeasures(coords) {
629
+ const triplets = ___default["default"].zip(rotate(coords, -1), coords, rotate(coords, 1));
630
+ const offsets = ___default["default"].map(triplets, function (triplet) {
631
+ const p = vector(triplet[1], triplet[0]);
632
+ const q = vector(triplet[2], triplet[1]);
633
+ // @ts-expect-error - TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'Coord'. | TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'readonly Coord[]'. | TS2345 - Argument of type 'number[]' is not assignable to parameter of type 'readonly Coord[]'.
634
+ const raw = Math.acos(dotProduct(p, q) / (magnitude(p) * magnitude(q)));
635
+ // @ts-expect-error - TS2556 - A spread argument must either have a tuple type or be passed to a rest parameter.
636
+ return sign(ccw(...triplet)) > 0 ? raw : -raw;
637
+ });
638
+ const sum = ___default["default"].reduce(offsets, function (memo, arg) {
639
+ return memo + arg;
640
+ }, 0);
641
+ return ___default["default"].map(offsets, function (offset) {
642
+ return sum > 0 ? Math.PI - offset : Math.PI + offset;
643
+ });
644
+ }
645
+
646
+ // Whether two polygons are similar (or if specified, congruent)
647
+ function similar(coords1, coords2, tolerance) {
648
+ if (coords1.length !== coords2.length) {
649
+ return false;
650
+ }
651
+ const n = coords1.length;
652
+ const angles1 = angleMeasures(coords1);
653
+ const angles2 = angleMeasures(coords2);
654
+ const sides1 = sideLengths(coords1);
655
+ const sides2 = sideLengths(coords2);
656
+ for (let i = 0; i < 2 * n; i++) {
657
+ let angles = angles2.slice();
658
+ let sides = sides2.slice();
659
+
660
+ // Reverse angles and sides to allow matching reflected polygons
661
+ if (i >= n) {
662
+ angles.reverse();
663
+ sides.reverse();
664
+ // Since sides are calculated from two coordinates,
665
+ // simply reversing results in an off by one error
666
+ // @ts-expect-error - TS4104 - The type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.
667
+ sides = rotate(sides, 1);
668
+ }
669
+
670
+ // @ts-expect-error - TS4104 - The type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.
671
+ angles = rotate(angles, i);
672
+ // @ts-expect-error - TS4104 - The type 'readonly number[]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.
673
+ sides = rotate(sides, i);
674
+ if (perseusCore.approximateDeepEqual(angles1, angles)) {
675
+ const sidePairs = ___default["default"].zip(sides1, sides);
676
+ const factors = ___default["default"].map(sidePairs, function (pair) {
677
+ return pair[0] / pair[1];
678
+ });
679
+ const same = ___default["default"].all(factors, function (factor) {
680
+ return perseusCore.approximateEqual(factors[0], factor);
681
+ });
682
+ const congruentEnough = ___default["default"].all(sidePairs, function (pair) {
683
+ return kmath.number.equal(pair[0], pair[1], tolerance);
684
+ });
685
+ if (same && congruentEnough) {
686
+ return true;
687
+ }
688
+ }
689
+ }
690
+ return false;
691
+ }
692
+
693
+ // Given triangle with sides ABC return angle opposite side C in degrees
694
+ function lawOfCosines(a, b, c) {
695
+ return Math.acos((a * a + b * b - c * c) / (2 * a * b)) * 180 / Math.PI;
696
+ }
697
+ function canonicalSineCoefficients(_ref) {
698
+ let [amplitude, angularFrequency, phase, verticalOffset] = _ref;
699
+ // For a curve of the form f(x) = a * Sin(b * x - c) + d,
700
+ // this function ensures that a, b > 0, and c is its
701
+ // smallest possible positive value.
702
+
703
+ // Guarantee a > 0
704
+ if (amplitude < 0) {
705
+ amplitude *= -1;
706
+ angularFrequency *= -1;
707
+ phase *= -1;
708
+ }
709
+ const period = 2 * Math.PI;
710
+ // Guarantee b > 0
711
+ if (angularFrequency < 0) {
712
+ angularFrequency *= -1;
713
+ phase *= -1;
714
+ phase += period / 2;
715
+ }
716
+
717
+ // Guarantee c is smallest possible positive value
718
+ while (phase > 0) {
719
+ phase -= period;
720
+ }
721
+ while (phase < 0) {
722
+ phase += period;
723
+ }
724
+ return [amplitude, angularFrequency, phase, verticalOffset];
725
+ }
726
+
727
+ // e.g. rotate([1, 2, 3]) -> [2, 3, 1]
728
+ function rotate(array, n) {
729
+ n = typeof n === "undefined" ? 1 : n % array.length;
730
+ return array.slice(n).concat(array.slice(0, n));
731
+ }
732
+ function getLineEquation(first, second) {
733
+ if (perseusCore.approximateEqual(first[0], second[0])) {
734
+ return "x = " + first[0].toFixed(3);
735
+ }
736
+ const m = (second[1] - first[1]) / (second[0] - first[0]);
737
+ const b = first[1] - m * first[0];
738
+ return "y = " + m.toFixed(3) + "x + " + b.toFixed(3);
739
+ }
740
+
741
+ // Stolen from the wikipedia article
742
+ // http://en.wikipedia.org/wiki/Line-line_intersection
743
+ function getLineIntersection(
744
+ // TODO(LP-10725): update these to be 2-tuples
745
+ firstPoints, secondPoints) {
746
+ const x1 = firstPoints[0][0];
747
+ const y1 = firstPoints[0][1];
748
+ const x2 = firstPoints[1][0];
749
+ const y2 = firstPoints[1][1];
750
+ const x3 = secondPoints[0][0];
751
+ const y3 = secondPoints[0][1];
752
+ const x4 = secondPoints[1][0];
753
+ const y4 = secondPoints[1][1];
754
+ const determinant = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
755
+ if (Math.abs(determinant) < 1e-9) {
756
+ return "Lines are parallel";
757
+ }
758
+ const x = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / determinant;
759
+ const y = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / determinant;
760
+ return "Intersection: (" + x.toFixed(3) + ", " + y.toFixed(3) + ")";
761
+ }
762
+
763
+ var geometry = /*#__PURE__*/Object.freeze({
764
+ __proto__: null,
765
+ sign: sign,
766
+ ccw: ccw,
767
+ collinear: collinear,
768
+ intersects: intersects,
769
+ polygonSidesIntersect: polygonSidesIntersect,
770
+ vector: vector,
771
+ reverseVector: reverseVector,
772
+ clockwise: clockwise,
773
+ magnitude: magnitude,
774
+ angleMeasures: angleMeasures,
775
+ similar: similar,
776
+ lawOfCosines: lawOfCosines,
777
+ canonicalSineCoefficients: canonicalSineCoefficients,
778
+ rotate: rotate,
779
+ getLineEquation: getLineEquation,
780
+ getLineIntersection: getLineIntersection
781
+ });
782
+
783
+ // This file contains helper functions for working with angles.
784
+ function convertDegreesToRadians(degrees) {
785
+ return degrees / 180 * Math.PI;
786
+ }
787
+
788
+ // Returns a value between -180 and 180, inclusive. The angle is measured
789
+ // between the positive x-axis and the given vector.
790
+ function calculateAngleInDegrees(_ref) {
791
+ let [x, y] = _ref;
792
+ return Math.atan2(y, x) * 180 / Math.PI;
793
+ }
794
+
795
+ // Converts polar coordinates to cartesian. The th(eta) parameter is in degrees.
796
+ function polar(r, th) {
797
+ if (typeof r === "number") {
798
+ r = [r, r];
799
+ }
800
+ th = th * Math.PI / 180;
801
+ return [r[0] * Math.cos(th), r[1] * Math.sin(th)];
802
+ }
803
+ // This function calculates the angle between two points and an optional vertex.
804
+ // If the vertex is not provided, the angle is measured between the two points.
805
+ // This does not account for reflex angles or clockwise position.
806
+ const getAngleFromVertex = (point, vertex) => {
807
+ const x = point[0] - vertex[0];
808
+ const y = point[1] - vertex[1];
809
+ if (!x && !y) {
810
+ return 0;
811
+ }
812
+ return (180 + Math.atan2(-y, -x) * 180 / Math.PI + 360) % 360;
813
+ };
814
+
815
+ // This function calculates the clockwise angle between three points,
816
+ // and is used to generate the labels and equation strings of the
817
+ // current angle for the interactive graph.
818
+ const getClockwiseAngle = function (coords) {
819
+ let allowReflexAngles = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
820
+ const coordsCopy = [...coords];
821
+ // The coords are saved as [point1, vertex, point2] in the interactive graph
822
+ const areClockwise = clockwise([coordsCopy[0], coordsCopy[2], coordsCopy[1]]);
823
+
824
+ // We may need to reverse the coordinates if we allow
825
+ // reflex angles and the points are not in clockwise order.
826
+ const shouldReverseCoords = !areClockwise || allowReflexAngles;
827
+
828
+ // Reverse the coordinates accordingly to ensure the angle is calculated correctly
829
+ const clockwiseCoords = shouldReverseCoords ? coordsCopy.reverse() : coordsCopy;
830
+
831
+ // Calculate the angles between the two points and get the difference
832
+ // between the two angles to get the clockwise angle.
833
+ const startAngle = getAngleFromVertex(clockwiseCoords[0], clockwiseCoords[1]);
834
+ const endAngle = getAngleFromVertex(clockwiseCoords[2], clockwiseCoords[1]);
835
+ const angle = (startAngle + 360 - endAngle) % 360;
836
+ return angle;
837
+ };
838
+
839
+ var angles = /*#__PURE__*/Object.freeze({
840
+ __proto__: null,
841
+ convertDegreesToRadians: convertDegreesToRadians,
842
+ calculateAngleInDegrees: calculateAngleInDegrees,
843
+ polar: polar,
844
+ getAngleFromVertex: getAngleFromVertex,
845
+ getClockwiseAngle: getClockwiseAngle
846
+ });
847
+
848
+ // TODO: there's another, very similar getSinusoidCoefficients function
849
+ // they should probably be merged
850
+ function getSinusoidCoefficients(coords) {
851
+ // It's assumed that p1 is the root and p2 is the first peak
852
+ const p1 = coords[0];
853
+ const p2 = coords[1];
854
+
855
+ // Resulting coefficients are canonical for this sine curve
856
+ const amplitude = p2[1] - p1[1];
857
+ const angularFrequency = Math.PI / (2 * (p2[0] - p1[0]));
858
+ const phase = p1[0] * angularFrequency;
859
+ const verticalOffset = p1[1];
860
+ return [amplitude, angularFrequency, phase, verticalOffset];
861
+ }
862
+ // TODO: there's another, very similar getQuadraticCoefficients function
863
+ // they should probably be merged
864
+ function getQuadraticCoefficients(coords) {
865
+ const p1 = coords[0];
866
+ const p2 = coords[1];
867
+ const p3 = coords[2];
868
+ const denom = (p1[0] - p2[0]) * (p1[0] - p3[0]) * (p2[0] - p3[0]);
869
+ if (denom === 0) {
870
+ // Many of the callers assume that the return value is always defined.
871
+ // @ts-expect-error - TS2322 - Type 'undefined' is not assignable to type 'QuadraticCoefficient'.
872
+ return;
873
+ }
874
+ const a = (p3[0] * (p2[1] - p1[1]) + p2[0] * (p1[1] - p3[1]) + p1[0] * (p3[1] - p2[1])) / denom;
875
+ const b = (p3[0] * p3[0] * (p1[1] - p2[1]) + p2[0] * p2[0] * (p3[1] - p1[1]) + p1[0] * p1[0] * (p2[1] - p3[1])) / denom;
876
+ const c = (p2[0] * p3[0] * (p2[0] - p3[0]) * p1[1] + p3[0] * p1[0] * (p3[0] - p1[0]) * p2[1] + p1[0] * p2[0] * (p1[0] - p2[0]) * p3[1]) / denom;
877
+ return [a, b, c];
878
+ }
879
+
880
+ var coefficients = /*#__PURE__*/Object.freeze({
881
+ __proto__: null,
882
+ getSinusoidCoefficients: getSinusoidCoefficients,
883
+ getQuadraticCoefficients: getQuadraticCoefficients
884
+ });
885
+
515
886
  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
516
887
 
517
888
  var jquery = {exports: {}};
@@ -10548,11 +10919,14 @@ function add(a, b) {
10548
10919
  }
10549
10920
 
10550
10921
  exports.KhanMath = KhanMath;
10922
+ exports.angles = angles;
10923
+ exports.coefficients = coefficients;
10924
+ exports.geometry = geometry;
10551
10925
  exports.libVersion = libVersion;
10552
10926
  exports.line = line;
10553
10927
  exports.number = number;
10554
10928
  exports.point = point;
10555
10929
  exports.ray = ray;
10556
10930
  exports.sum = sum;
10557
- exports.vector = vector;
10931
+ exports.vector = vector$1;
10558
10932
  //# sourceMappingURL=index.js.map