flo-mat 4.1.4 → 4.1.5

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.
Files changed (57) hide show
  1. package/__tests__/cp-node/circle-identity.spec.ts +56 -0
  2. package/__tests__/find-2-prong/get-medial/dd-get-medial-point-coeffs-same-curve.spec.ts +7 -5
  3. package/__tests__/find-2-prong/get-medial/dd-get-medial-point-coeffs.spec.ts +4 -2
  4. package/browser/index.js +2606 -2161
  5. package/browser/index.min.js +1 -1
  6. package/node/add-n-prong.ts/join-spokes.js +3 -2
  7. package/node/add-n-prong.ts/join-spokes.js.map +1 -1
  8. package/node/cp-node/fs/enhance-cp-node.d.ts +9 -9
  9. package/node/cp-node/fs/get-angle-between-mat-curves.d.ts +1 -1
  10. package/node/cp-node/fs/get-angle-between-mat-curves.js +2 -1
  11. package/node/cp-node/fs/get-angle-between-mat-curves.js.map +1 -1
  12. package/node/cp-node/fs/get-edge-direction.js +3 -2
  13. package/node/cp-node/fs/get-edge-direction.js.map +1 -1
  14. package/node/cp-node/fs/get-implied-boundary-bezier-between.d.ts +1 -1
  15. package/node/cp-node/fs/get-implied-boundary-bezier-between.js +3 -2
  16. package/node/cp-node/fs/get-implied-boundary-bezier-between.js.map +1 -1
  17. package/node/cp-node/fs/get-mat-curve-between.d.ts +1 -0
  18. package/node/cp-node/fs/get-mat-curve-between.js +1 -0
  19. package/node/cp-node/fs/get-mat-curve-between.js.map +1 -1
  20. package/node/cp-node/fs/is-fully-terminating.d.ts +1 -1
  21. package/node/cp-node/fs/is-fully-terminating.js +3 -5
  22. package/node/cp-node/fs/is-fully-terminating.js.map +1 -1
  23. package/node/cp-node/fs/is-on-same-circle.d.ts +3 -0
  24. package/node/cp-node/fs/is-on-same-circle.js +4 -4
  25. package/node/cp-node/fs/is-on-same-circle.js.map +1 -1
  26. package/node/cp-node/stringification/from-stringifyable.js +16 -0
  27. package/node/cp-node/stringification/from-stringifyable.js.map +1 -1
  28. package/node/find-2-prong/add-2-prong.js +6 -2
  29. package/node/find-2-prong/add-2-prong.js.map +1 -1
  30. package/node/find-2-prong/calc-seperation-tolerance.js +2 -2
  31. package/node/find-2-prong/calc-seperation-tolerance.js.map +1 -1
  32. package/node/find-3-prong/find-3-prong-for-delta3s.js +1 -1
  33. package/node/find-3-prong/find-3-prong-for-delta3s.js.map +1 -1
  34. package/node/geometry/get-closest-squared-distance-to-rotated-rect.js +2 -1
  35. package/node/geometry/get-closest-squared-distance-to-rotated-rect.js.map +1 -1
  36. package/node/mat/get-closeby-cp-if-exist.js +2 -1
  37. package/node/mat/get-closeby-cp-if-exist.js.map +1 -1
  38. package/node/point-on-shape/point-on-shape.d.ts +5 -0
  39. package/node/reconstruct-from-mat/reconstruct-from-mat.js.map +1 -1
  40. package/package.json +12 -12
  41. package/src/add-n-prong.ts/join-spokes.ts +4 -2
  42. package/src/cp-node/fs/get-angle-between-mat-curves.ts +4 -2
  43. package/src/cp-node/fs/get-edge-direction.ts +4 -2
  44. package/src/cp-node/fs/get-implied-boundary-bezier-between.ts +6 -6
  45. package/src/cp-node/fs/get-mat-curve-between.ts +1 -0
  46. package/src/cp-node/fs/is-fully-terminating.ts +3 -7
  47. package/src/cp-node/fs/is-on-same-circle.ts +6 -7
  48. package/src/cp-node/stringification/from-stringifyable.ts +17 -0
  49. package/src/find-2-prong/add-2-prong.ts +7 -2
  50. package/src/find-2-prong/calc-seperation-tolerance.ts +2 -2
  51. package/src/find-3-prong/find-3-prong-for-delta3s.ts +1 -1
  52. package/src/geometry/get-closest-squared-distance-to-rotated-rect.ts +4 -4
  53. package/src/mat/get-closeby-cp-if-exist.ts +3 -1
  54. package/src/point-on-shape/point-on-shape.ts +5 -0
  55. package/src/utils/deg-to-rad.ts +4 -2
  56. package/src/utils/rad-to-deg.ts +4 -1
  57. package/webpack.config.cjs +7 -2
@@ -4,6 +4,8 @@ import { toUnitVector, fromTo, rotate, translate, rotate90Degrees, reverse as re
4
4
  import { tangent } from 'flo-bezier3';
5
5
  import { isPosSharpCorner } from '../../point-on-shape/is-pos-sharp-corner.js';
6
6
 
7
+ const { sqrt } = Math;
8
+
7
9
 
8
10
  /**
9
11
  * Returns a line segment of unit length starting in the given Vertex center and
@@ -54,8 +56,8 @@ function getEdgeDirection(
54
56
  // Recall the identities sin(acos(x)) = sqrt(1-x^2), etc. Also
55
57
  // recall the half angle formulas. Then the rotation matrix, R, can
56
58
  // be calculated.
57
- const cosθ = Math.sqrt((1 + x)/2);
58
- const sinθ = Math.sqrt((1 - x)/2);
59
+ const cosθ = sqrt((1 + x)/2);
60
+ const sinθ = sqrt((1 - x)/2);
59
61
 
60
62
  vDir = rotate(sinθ, cosθ, tan2);
61
63
  }
@@ -1,8 +1,8 @@
1
+ import type { CpNode } from '../cp-node.js';
1
2
  import { tangent } from 'flo-bezier3';
2
- import {
3
- fromTo, dot, cross, translate, lineLineIntersection, toUnitVector
4
- } from 'flo-vector2d';
5
- import { CpNode } from '../cp-node.js';
3
+ import { fromTo, dot, cross, translate, lineLineIntersection, toUnitVector } from 'flo-vector2d';
4
+
5
+ const { abs } = Math;
6
6
 
7
7
 
8
8
  /** @internal */
@@ -56,8 +56,8 @@ function getImpliedBoundaryBezierBetween(
56
56
  const w1 = fromTo(lA[0], lA[1]); // This is a unit vector
57
57
  const w2 = fromTo(lB[0], lB[1]); // This is a unit vector
58
58
 
59
- const d1 = Math.abs(cross(c, w1)) / (3*3);
60
- const d2 = Math.abs(cross(c, w2)) / (3*3);
59
+ const d1 = abs(cross(c, w1)) / (3*3);
60
+ const d2 = abs(cross(c, w2)) / (3*3);
61
61
 
62
62
  if (d1 > TOLERANCE_ADD_2PRONG || d2 > TOLERANCE_ADD_2PRONG) {
63
63
  // not within tolerance
@@ -17,6 +17,7 @@ const TOLERANCE_USE_LINE = 0.0001; // else cubic
17
17
  /**
18
18
  * Returns the bezier curve from the maximal disk of one `CpNode` to another
19
19
  * `CpNode`'s maximal disk.
20
+ *
20
21
  * @param cpNodeFrom
21
22
  * @param cpNodeTo
22
23
  */
@@ -5,13 +5,10 @@ import { isTrivial } from "./is-trivial.js";
5
5
 
6
6
 
7
7
  /**
8
- * Like isTerminating() but only returns true if all cpNodes on the circle
8
+ * Like `isTerminating` but only returns true if all `CpNode`s on the circle
9
9
  * (except this.prevOnCircle) is terminating.
10
10
  */
11
11
  function isFullyTerminating(cpNode: CpNode) {
12
- // const otherOnCircle = getAllOnCircle(cpNode.prevOnCircle, true);
13
-
14
- // return otherOnCircle.every(isTerminating);
15
12
  if (!isTerminating(cpNode)) {
16
13
  return false;
17
14
  }
@@ -24,9 +21,8 @@ function isFullyTerminating(cpNode: CpNode) {
24
21
  cpNode = cpNode.prev;
25
22
  }
26
23
 
27
- const otherOnCircle = getAllOnCircle(cpNode.prevOnCircle, true);
28
-
29
- return otherOnCircle.every(isTerminating);
24
+ return getAllOnCircle(cpNode.prevOnCircle, true)
25
+ .every(isTerminating);
30
26
  }
31
27
 
32
28
 
@@ -1,11 +1,13 @@
1
1
  import { CpNode } from "../cp-node.js";
2
- import { getAllOnCircle } from "./get-all-on-circle.js";
3
2
 
4
3
 
5
4
  /**
6
- * Returns true if the 2 given `CpNode`s are on the same maximal disk
5
+ * Returns true if the 2 given `CpNode`s are on the same maximal disk
7
6
  * circle.
8
- *
7
+ *
8
+ * * O(1): all `CpNode`s on the same on-circle ring share the same `Circle`
9
+ * object, and no other ring does (see `PointOnShape.circle`)
10
+ *
9
11
  * @param cpNode1 A `CpNode`.
10
12
  * @param cpNode2 Another `CpNode`
11
13
  */
@@ -13,10 +15,7 @@ function isOnSameCircle(
13
15
  cpNode1: CpNode,
14
16
  cpNode2: CpNode) {
15
17
 
16
- // const cpNodes = getAllOnCircle(cpNode1, true);
17
- const cpNodes = getAllOnCircle(cpNode1);
18
-
19
- return cpNodes.indexOf(cpNode2) >= 0;
18
+ return cpNode1.pointOnShape.circle === cpNode2.pointOnShape.circle;
20
19
  }
21
20
 
22
21
 
@@ -1,7 +1,9 @@
1
1
  import type { PointOnShape } from "../../point-on-shape/point-on-shape.js";
2
2
  import type { CpNode } from "../cp-node";
3
3
  import type { CpNodeStringifyable } from "./cp-node-stringifyable";
4
+ import type { Mutable } from "../../utils/mutable.js";
4
5
  import { EDGES } from "./cp-node-stringifyable";
6
+ import { getAllOnCircle } from "../fs/get-all-on-circle.js";
5
7
  import { loopFromStringifyable } from './loop-from-stringifyable.js';
6
8
 
7
9
 
@@ -51,6 +53,21 @@ function fromStringifyable(
51
53
  }
52
54
  }
53
55
 
56
+ //--------------------------------------------------------------------------
57
+ // Third pass: one shared `Circle` object per on-circle ring, as when the
58
+ // MAT was built (the JSON gave every contact point its own copy).
59
+ //--------------------------------------------------------------------------
60
+ const done = new Set<CpNode>();
61
+ for (const cpNode of cpNodes) {
62
+ if (done.has(cpNode)) { continue; }
63
+
64
+ const { circle } = cpNode.pointOnShape;
65
+ for (const cp of getAllOnCircle(cpNode)) {
66
+ done.add(cp);
67
+ (cp.pointOnShape as Mutable<PointOnShape>).circle = circle;
68
+ }
69
+ }
70
+
54
71
  return cpNodes[0];
55
72
  }
56
73
 
@@ -83,12 +83,17 @@ function closeHole(
83
83
 
84
84
  const [cpNodeSource, cpNodeAntipode] = cpNodes as Mutable<CpNode>[];
85
85
 
86
+ // The twins form their own on-circle ring (a separate MAT vertex - that
87
+ // is what cuts the hole), so they get their own (equal) `Circle` object:
88
+ // one `Circle` object per ring.
89
+ const twinCircle: Circle = { ...cpNodeSource.pointOnShape.circle };
90
+
86
91
  // Antipode - create and insert twin
87
92
  const posAntipode = cpNodeAntipode.pointOnShape;
88
93
  const cpNodeAntipodeTwin = insertCpNode(
89
94
  true, true, false,
90
95
  cpTrees.get(posAntipode.curve.loop)!,
91
- { ...posAntipode, order2: +1 },
96
+ { ...posAntipode, circle: twinCircle, order2: +1 },
92
97
  cpNodeAntipode,
93
98
  undefined, // unused
94
99
  meta.lastInsertId
@@ -101,7 +106,7 @@ function closeHole(
101
106
  const cpNodeSourceTwin = insertCpNode(
102
107
  true, true, false,
103
108
  cpTrees.get(posSource.curve.loop)!,
104
- { ...posSource!, order2: -1 },
109
+ { ...posSource!, circle: twinCircle, order2: -1 },
105
110
  cpNodeSource.prev,
106
111
  undefined, // unused
107
112
  meta.lastInsertId
@@ -89,10 +89,10 @@ export { calcSeperationTolerance }
89
89
 
90
90
 
91
91
  // function degToRad(degrees: number) {
92
- // return degrees/360*2*Math.PI;
92
+ // return degrees/360*2*PI;
93
93
  // }
94
94
  // function radToDeg(rad: number) {
95
- // return rad*360/2/Math.PI;
95
+ // return rad*360/2/PI;
96
96
  // }
97
97
 
98
98
 
@@ -174,7 +174,7 @@ function find3ProngForDelta3s(
174
174
  const v2 = toUnitVector( tangent(pos.curve.ps, pos.t) );
175
175
 
176
176
  // Cross is more numerically stable than Vector.dot at angles a
177
- // multiple of `Math.PI` **and** is close to the actual angle value
177
+ // multiple of π **and** is close to the actual angle value
178
178
  // and can thus just be added to cone method of looking at
179
179
  // tolerance.
180
180
 
@@ -1,6 +1,6 @@
1
- import {
2
- squaredDistanceBetweenPointAndLineSegment, squaredDistanceBetween
3
- } from 'flo-vector2d';
1
+ import { squaredDistanceBetweenPointAndLineSegment, squaredDistanceBetween } from 'flo-vector2d';
2
+
3
+ const { min } = Math;
4
4
 
5
5
 
6
6
  /**
@@ -23,7 +23,7 @@ function getClosestSquaredDistanceToRotatedRect(ps: number[][], p: number[]) {
23
23
  return 0; // Inside rotated rect
24
24
  }
25
25
 
26
- return Math.min(...ds);
26
+ return min(...ds);
27
27
  }
28
28
 
29
29
 
@@ -5,10 +5,12 @@ import type { MatMeta } from './mat-meta.js';
5
5
  import { distanceBetween, toUnitVector, fromTo, dot } from 'flo-vector2d';
6
6
  import { getCpNodeNeighbors } from './get-cp-node-neighbors.js';
7
7
 
8
+ const { cos, PI: π } = Math;
9
+
8
10
 
9
11
  /** @internal */
10
12
  const DEGREES = 1;
11
- const ANGLE_THRESHOLD = Math.cos(DEGREES * (Math.PI / 180));
13
+ const ANGLE_THRESHOLD = cos(DEGREES * (π/180));
12
14
 
13
15
 
14
16
  /**
@@ -44,6 +44,11 @@ interface PointOnShape extends PrePointOnShape {
44
44
  * The (cached) maximal disk circle touching this point.
45
45
  * Calculated from `curve` and `t` (if 2-prong source point, else
46
46
  * from `curve` and `t` of the antipodal 2-prong point).
47
+ *
48
+ * * the same `Circle` object is shared by all `CpNode`s on the same
49
+ * on-circle ring (`nextOnCircle`), and only by them - so object
50
+ * identity identifies the MAT vertex (hole-closer twins form their own
51
+ * ring, with their own equal circle)
47
52
  */
48
53
  readonly circle: Circle;
49
54
  /** Internally used to order two points lying at the same planar point. */
@@ -1,7 +1,9 @@
1
1
 
2
+ const { PI: π } = Math;
3
+
2
4
  function degToRad(degrees: number) {
3
- return degrees/360*2*Math.PI;
5
+ return degrees/180*π;
4
6
  }
5
7
 
6
8
 
7
- export { degToRad };
9
+ export { degToRad }
@@ -1,6 +1,9 @@
1
1
 
2
+ const { PI: π } = Math;
3
+
4
+
2
5
  function radToDeg(rad: number) {
3
- return rad*180/Math.PI;
6
+ return rad*180/π;
4
7
  }
5
8
 
6
9
 
@@ -38,8 +38,13 @@ const config_Basic = (env, argv) => {
38
38
  rules: [{
39
39
  test: /\.tsx?$/,
40
40
  use: [{
41
- loader: 'ts-loader',
42
- options: { silent: true }
41
+ loader: 'swc-loader',
42
+ options: {
43
+ jsc: {
44
+ parser: { syntax: 'typescript' },
45
+ target: 'esnext'
46
+ }
47
+ }
43
48
  }],
44
49
  exclude: /node_modules/,
45
50
  sideEffects: false