flo-mat 3.0.13 → 3.0.15

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 (138) hide show
  1. package/__tests__/cp-node/check-clone-eql-calc.spec.ts +58 -0
  2. package/__tests__/cp-node/compare-cp-nodes-by-value.ts +35 -0
  3. package/__tests__/cp-node/compare-loops-by-value.ts +40 -0
  4. package/__tests__/cp-node/compare-poss-by-value.ts +25 -0
  5. package/__tests__/cp-node/fs/clone.spec.ts +19 -3
  6. package/__tests__/cp-node/fs/find-first.spec.ts +13 -3
  7. package/__tests__/cp-node/fs/get-all-between.spec.ts +20 -3
  8. package/__tests__/cp-node/fs/get-all-on-circle.spec.ts +2 -2
  9. package/__tests__/cp-node/fs/get-all-on-loop.spec.ts +16 -3
  10. package/__tests__/cp-node/fs/get-all-vertices.spec.ts +14 -3
  11. package/__tests__/cp-node/fs/get-children.spec.ts +18 -3
  12. package/__tests__/cp-node/fs/get-non-terminating-on-circle.spec.ts +14 -3
  13. package/__tests__/cp-node/fs/get-prong-count.spec.ts +16 -3
  14. package/__tests__/cp-node/fs/get-real-prong-count.spec.ts +11 -3
  15. package/__tests__/cp-node/fs/get-terminating-on-circle.spec.ts +20 -3
  16. package/__tests__/cp-node/fs/is-fully-terminating.spec.ts +16 -3
  17. package/__tests__/cp-node/fs/is-on-same-circle.spec.ts +20 -3
  18. package/__tests__/cp-node/fs/is-one-prong.spec.ts +16 -3
  19. package/__tests__/cp-node/fs/is-sharp.spec.ts +10 -3
  20. package/__tests__/cp-node/fs/is-single-3-prong.spec.ts +13 -3
  21. package/__tests__/cp-node/fs/is-special.spec.ts +12 -3
  22. package/__tests__/cp-node/fs/is-terminating.spec.ts +15 -3
  23. package/__tests__/cp-node/fs/is-trivial.spec.ts +13 -3
  24. package/__tests__/cp-node/fs/is-two-prong.spec.ts +11 -3
  25. package/__tests__/cp-node/fs/is-vertex-special.spec.ts +13 -3
  26. package/__tests__/cp-node/fs/is-vertex.spec.ts +14 -3
  27. package/__tests__/cp-node/fs/iterate-all-on-loop.spec.ts +13 -3
  28. package/__tests__/cp-node/fs/traverse-all-forward.spec.ts +10 -3
  29. package/__tests__/cp-node/fs/traverse-cp.spec.ts +9 -3
  30. package/__tests__/cp-node/fs/traverse-edges.spec.ts +13 -3
  31. package/__tests__/cp-node/fs/traverse-vertices.spec.ts +12 -3
  32. package/__tests__/cp-node/random-walk.ts +33 -0
  33. package/__tests__/cp-node/stringification/from-stringifyable.spec.ts +3 -0
  34. package/__tests__/cp-node/stringification/loop-from-stringifyable.spec.ts +4 -0
  35. package/__tests__/cp-node/stringification/loop-to-stringifyable.spec.ts +19 -0
  36. package/__tests__/cp-node/stringification/to-stringifyable.spec.ts +34 -0
  37. package/__tests__/get-mats1.ts +125 -0
  38. package/__tests__/jsog/check-jsog-eql-calc.spec.ts +47 -67
  39. package/__tests__/jsog/decode-jsog.ts +88 -85
  40. package/__tests__/jsog/mat-dummy-1.ts +19 -0
  41. package/__tests__/jsog/mat-dummys.ts +6197 -6195
  42. package/__tests__/jsog/to-jsog-breath-first.ts +110 -107
  43. package/__tests__/jsog/to-jsog-depth-first.ts +58 -55
  44. package/browser/index.js +7002 -6298
  45. package/browser/index.min.js +1 -1
  46. package/jest.config.cjs +1 -0
  47. package/node/closest-boundary-point/foot-and-endpoint-info.d.ts +1 -1
  48. package/node/closest-boundary-point/get-close-boundary-points-certified.d.ts +3 -3
  49. package/node/closest-boundary-point/get-close-boundary-points-certified.js +1 -1
  50. package/node/closest-boundary-point/get-close-boundary-points-certified.js.map +1 -1
  51. package/node/closest-boundary-point/get-potential-closest-points-on-curve-certified.d.ts +2 -2
  52. package/node/closest-boundary-point/get-potential-closest-points-on-curve-certified.js +7 -7
  53. package/node/closest-boundary-point/get-potential-closest-points-on-curve-certified.js.map +1 -1
  54. package/node/cp-node/cp-node.d.ts +2 -2
  55. package/node/cp-node/fs/clone.d.ts +1 -1
  56. package/node/cp-node/fs/clone.js +17 -13
  57. package/node/cp-node/fs/clone.js.map +1 -1
  58. package/node/cp-node/fs/enhance-cp-node.d.ts +2 -2
  59. package/node/cp-node/fs/find-first.d.ts +9 -2
  60. package/node/cp-node/fs/find-first.js +12 -9
  61. package/node/cp-node/fs/find-first.js.map +1 -1
  62. package/node/cp-node/fs/get-all-on-loop.js +5 -6
  63. package/node/cp-node/fs/get-all-on-loop.js.map +1 -1
  64. package/node/cp-node/fs/get-edge-direction.d.ts +1 -1
  65. package/node/cp-node/fs/get-edge-direction.js.map +1 -1
  66. package/node/cp-node/fs/is-on-same-circle.d.ts +1 -0
  67. package/node/cp-node/fs/is-on-same-circle.js +1 -0
  68. package/node/cp-node/fs/is-on-same-circle.js.map +1 -1
  69. package/node/debug/functions/draw-elem/draw-dull-corner.d.ts +1 -1
  70. package/node/debug/functions/draw-elem/draw-dull-corner.js +1 -1
  71. package/node/debug/functions/draw-elem/draw-dull-corner.js.map +1 -1
  72. package/node/debug/functions/draw-elem/draw-sharp-corner.d.ts +1 -1
  73. package/node/debug/functions/draw-elem/draw-sharp-corner.js +2 -1
  74. package/node/debug/functions/draw-elem/draw-sharp-corner.js.map +1 -1
  75. package/node/find-mat/find-mats.js +7 -2
  76. package/node/find-mat/find-mats.js.map +1 -1
  77. package/node/find-mat/get-meta.d.ts +4 -4
  78. package/node/find-mat/get-meta.js +1 -1
  79. package/node/find-mat/get-meta.js.map +1 -1
  80. package/node/geometry/circle.d.ts +4 -3
  81. package/node/geometry/circle.js +0 -7
  82. package/node/geometry/circle.js.map +1 -1
  83. package/node/index.d.ts +2 -2
  84. package/node/index.js +1 -0
  85. package/node/index.js.map +1 -1
  86. package/node/mat/curve-piece.d.ts +3 -3
  87. package/node/mat/get-boundary-piece-beziers.d.ts +2 -2
  88. package/node/mat/mat-meta.d.ts +4 -4
  89. package/node/mat/simplify-mat.d.ts +10 -8
  90. package/node/mat/simplify-mat.js +12 -10
  91. package/node/mat/simplify-mat.js.map +1 -1
  92. package/node/point-on-shape/create-pos.d.ts +2 -2
  93. package/node/point-on-shape/create-pos.js.map +1 -1
  94. package/node/point-on-shape/point-on-shape.d.ts +6 -6
  95. package/node/svg/get-loop-bounds.d.ts +2 -2
  96. package/node/svg/get-loop-bounds.js +1 -1
  97. package/node/svg/get-loop-bounds.js.map +1 -1
  98. package/package.json +10 -10
  99. package/src/closest-boundary-point/foot-and-endpoint-info.ts +1 -1
  100. package/src/closest-boundary-point/get-close-boundary-points-certified.ts +5 -5
  101. package/src/closest-boundary-point/get-potential-closest-points-on-curve-certified.ts +9 -9
  102. package/src/cp-node/cp-node.ts +8 -3
  103. package/src/cp-node/fs/add-distance-from.ts +37 -37
  104. package/src/cp-node/fs/clone.ts +23 -17
  105. package/src/cp-node/fs/find-first.ts +14 -11
  106. package/src/cp-node/fs/get-all-on-loop.ts +5 -6
  107. package/src/cp-node/fs/get-boundary-bezier-parts-to-next.ts +1 -1
  108. package/src/cp-node/fs/get-edge-direction.ts +3 -5
  109. package/src/cp-node/fs/is-on-same-circle.ts +1 -0
  110. package/src/cp-node/stringification/cp-node-stringifyable.ts +68 -0
  111. package/src/cp-node/stringification/from-stringifyable.ts +57 -0
  112. package/src/cp-node/stringification/loop-from-stringifyable.ts +15 -0
  113. package/src/cp-node/stringification/loop-stringifyable.ts +8 -0
  114. package/src/cp-node/stringification/loop-to-stringifyable.ts +14 -0
  115. package/src/cp-node/stringification/to-stringifyable.ts +71 -0
  116. package/src/curve/curve.ts +31 -33
  117. package/src/debug/functions/draw-elem/draw-dull-corner.ts +2 -2
  118. package/src/debug/functions/draw-elem/draw-sharp-corner.ts +4 -3
  119. package/src/find-mat/find-mats.ts +8 -2
  120. package/src/find-mat/get-meta.ts +7 -6
  121. package/src/geometry/circle.ts +5 -12
  122. package/src/index.ts +3 -4
  123. package/src/mat/curve-piece.ts +3 -3
  124. package/src/mat/get-boundary-piece-beziers.ts +3 -3
  125. package/src/mat/mat-meta.ts +4 -4
  126. package/src/mat/simplify-mat-map-only.ts +110 -110
  127. package/src/mat/simplify-mat.ts +15 -13
  128. package/src/point-on-shape/create-pos.ts +3 -3
  129. package/src/point-on-shape/point-on-shape.ts +6 -6
  130. package/src/svg/get-loop-bounds.ts +4 -5
  131. package/__tests__/cp-node/fs/add-distance-from.spec.ts +0 -7
  132. package/__tests__/cp-node/fs/cp-nodes-to-boundary-beziers.spec.ts +0 -7
  133. package/__tests__/cp-node/fs/create-cp-node.spec.ts +0 -7
  134. package/__tests__/cp-node/fs/enhance-cp-node.spec.ts +0 -7
  135. package/__tests__/jsog/get-mats1.ts +0 -41
  136. package/node/curve/curve.d.ts +0 -33
  137. package/node/curve/curve.js +0 -2
  138. package/node/curve/curve.js.map +0 -1
@@ -0,0 +1,58 @@
1
+ import { test } from '@jest/globals';
2
+
3
+ test.todo('Ignore this test for now');
4
+
5
+
6
+ // import type { CpNode } from '../../src/cp-node/cp-node.js';
7
+ // import { expect, test } from '@jest/globals';
8
+ // import { getAllOnLoop } from '../../src/cp-node/fs/get-all-on-loop.js';
9
+ // import { randomWalk } from './random-walk.js';
10
+ // import { getMats1 } from '../get-mats1.js';
11
+
12
+
13
+ // test('Check MAT objects equal (after clone)', function() {
14
+ // const mats1 = getMats1(); // Calculates MAT from shape
15
+
16
+ // // too hard for Jest due to circular references
17
+ // // expect(mats_obj1).toEqual(mats_calc1);
18
+
19
+ // // Fast path: check root array structure and length
20
+ // expect(Array.isArray(mats1_)).toBe(true);
21
+ // expect(Array.isArray(mats1)).toBe(true);
22
+ // expect(mats1_.length).toBe(mats1.length);
23
+
24
+ // // Verify key properties of the MAT objects instead of deep comparison
25
+ // const mats1_0_ = mats1_[0];
26
+ // const mats1_0 = mats1[0];
27
+
28
+ // // Check critical structure exists
29
+ // expect(mats1_0_).toHaveProperty('cpNode');
30
+ // expect(mats1_0).toHaveProperty('cpNode');
31
+
32
+ // // Verify circular reference integrity
33
+ // if (mats1_0_.cpNode && mats1_0_.cpNode.nextOnCircle) {
34
+ // expect(mats1_0_.cpNode.nextOnCircle).toBeDefined();
35
+ // }
36
+
37
+ // getAllOnLoop(mats1_0_.cpNode).length; //?
38
+
39
+ // // Perform a random walk on the calculated MAT to ensure it behaves as expected
40
+ // let testCpNode = mats1_0.cpNode;
41
+ // let testCpNode_ = mats1_0_.cpNode;
42
+
43
+ // const N = 10;
44
+ // let reachCpNodes = new Set<CpNode>();
45
+ // for (let i=0; i<N; i++) {
46
+ // testCpNode = randomWalk(testCpNode, i*N, N);
47
+ // testCpNode_ = randomWalk(testCpNode_, i*N, N);
48
+
49
+ // // testCpNode.cp.pointOnShape.p; //?
50
+ // // testCpNode_.cp.pointOnShape.p;//?
51
+
52
+ // reachCpNodes.add(testCpNode);
53
+
54
+ // expect(testCpNode.cp.pointOnShape).toEqual(testCpNode_.cp.pointOnShape);
55
+ // }
56
+
57
+ // reachCpNodes.size; //?
58
+ // });
@@ -0,0 +1,35 @@
1
+ import { CpNode } from "../../src/cp-node/cp-node.js";
2
+ import { comparePossByValue } from "./compare-poss-by-value.js";
3
+ import { randomWalk } from "./random-walk.js";
4
+
5
+
6
+ function compareCpNodesByValue(
7
+ cpNode1: CpNode,
8
+ cpNode2: CpNode): boolean {
9
+
10
+ // Perform a random walk on the calculated MAT to ensure it behaves as expected
11
+
12
+ const N = 10;
13
+ let reachCpNodes1 = new Set<CpNode>();
14
+ let reachCpNodes2 = new Set<CpNode>();
15
+ for (let i=0; i<N; i++) {
16
+ cpNode1 = randomWalk(cpNode1, i*N, N);
17
+ cpNode2 = randomWalk(cpNode2, i*N, N);
18
+
19
+ reachCpNodes1.add(cpNode1);
20
+ reachCpNodes2.add(cpNode2);
21
+
22
+ if (!comparePossByValue(cpNode1.cp.pointOnShape, cpNode2.cp.pointOnShape)) {
23
+ return false;
24
+ }
25
+
26
+ cpNode2.cp.pointOnShape;
27
+ }
28
+
29
+ if (reachCpNodes1.size !== reachCpNodes2.size) { return false; }
30
+
31
+ return true;
32
+ }
33
+
34
+
35
+ export { compareCpNodesByValue }
@@ -0,0 +1,40 @@
1
+ import { Loop } from "flo-boolean";
2
+
3
+
4
+ function compareLoopsByValue(
5
+ loop1: Loop,
6
+ loop2: Loop): boolean {
7
+
8
+ const { idx: idx1, beziers: beziers1, curves: curves1 } = loop1;
9
+ const { idx: idx2, beziers: beziers2, curves: curves2 } = loop2;
10
+
11
+ if (idx1 !== idx2) { return false; }
12
+ if (beziers1.length !== beziers2.length) { return false; }
13
+ for (let i=0; i<beziers1.length; i++) {
14
+ const b1 = beziers1[i];
15
+ const b2 = beziers2[i];
16
+ if (b1.length !== b2.length) { return false; }
17
+ for (let j=0; j<b1.length; j++) {
18
+ const p1 = b1[j];
19
+ const p2 = b2[j];
20
+ if (p1[0] !== p2[0] || p1[1] !== p2[1]) { return false; }
21
+ }
22
+ }
23
+
24
+ for (let i=0; i<curves1.length; i++) {
25
+ const c1 = curves1[i];
26
+ const c2 = curves2[i];
27
+
28
+ if (c1.idx !== c2.idx) { return false; }
29
+ if (!c1.next || !c2.next || !c1.prev || !c2.prev ||
30
+ !c1.ps || !c2.ps) {
31
+
32
+ return false;
33
+ }
34
+ }
35
+
36
+ return true;
37
+ }
38
+
39
+
40
+ export { compareLoopsByValue }
@@ -0,0 +1,25 @@
1
+ import { PointOnShape } from "../../src/point-on-shape/point-on-shape.js";
2
+
3
+
4
+ function comparePossByValue(
5
+ pos1: PointOnShape, pos2: PointOnShape): boolean {
6
+
7
+ if (pos1.t !== pos2.t) { return false; }
8
+
9
+ if (pos1.p[0] !== pos2.p[0]) { return false; }
10
+ if (pos1.p[1] !== pos2.p[1]) { return false; }
11
+ if (pos1.curve.idx !== pos2.curve.idx) { return false; }
12
+ if (pos1.curve.loop.idx !== pos2.curve.loop.idx) { return false; }
13
+ if (pos1.isSource !== pos2.isSource) { return false; }
14
+
15
+ for (let i=0; i<pos1.p.length; i++) {
16
+ if (pos1.p[i] !== pos2.p[i]) {
17
+ return false;
18
+ }
19
+ }
20
+
21
+ return true;
22
+ }
23
+
24
+
25
+ export { comparePossByValue }
@@ -1,7 +1,23 @@
1
1
  import { expect, test } from '@jest/globals';
2
2
  import { clone } from '../../../src/cp-node/fs/clone.js';
3
+ import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
4
+ import { getMats1 } from '../../get-mats1.js';
3
5
 
4
- test.skip('clone [STUB]', () => {
5
- // TODO: implement test
6
- expect(true).toBe(true);
6
+
7
+ test('clone', function() {
8
+ const { cpNode } = getMats1()[0];
9
+ const cloned = clone(cpNode);
10
+
11
+ expect(cloned === cpNode).toBe(false);
12
+
13
+ const origLoop = getAllOnLoop(cpNode);
14
+ const cloneLoop = getAllOnLoop(cloned);
15
+ expect(cloneLoop.length).toBe(origLoop.length);
16
+
17
+ expect(cloned.next.prev === cloned).toBe(true);
18
+ expect(cloned.prev.next === cloned).toBe(true);
19
+ expect(cloned.nextOnCircle.prevOnCircle === cloned).toBe(true);
20
+ expect(cloned.prevOnCircle.nextOnCircle === cloned).toBe(true);
21
+
22
+ expect(cloned.next !== cpNode.next).toBe(true);
7
23
  });
@@ -1,7 +1,17 @@
1
1
  import { expect, test } from '@jest/globals';
2
2
  import { findFirst } from '../../../src/cp-node/fs/find-first.js';
3
+ import { getMats1 } from '../../get-mats1.js';
3
4
 
4
- test.skip('findFirst [STUB]', () => {
5
- // TODO: implement test
6
- expect(true).toBe(true);
5
+
6
+ test('findFirst', function() {
7
+ const { cpNode } = getMats1()[0];
8
+
9
+ // Always-true predicate: returns the start node
10
+ expect(findFirst(() => true, cpNode) === cpNode).toBe(true);
11
+
12
+ // Always-false predicate: returns undefined
13
+ expect(findFirst(() => false, cpNode)).toBeUndefined();
14
+
15
+ // Predicate matching cpNode.next: returns cpNode.next
16
+ expect(findFirst(n => n === cpNode.next, cpNode) === cpNode.next).toBe(true);
7
17
  });
@@ -1,7 +1,24 @@
1
1
  import { expect, test } from '@jest/globals';
2
2
  import { getAllBetween } from '../../../src/cp-node/fs/get-all-between.js';
3
+ import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
4
+ import { getMats1 } from '../../get-mats1.js';
3
5
 
4
- test.skip('getAllBetween [STUB]', () => {
5
- // TODO: implement test
6
- expect(true).toBe(true);
6
+
7
+ test('getAllBetween', function() {
8
+ const { cpNode } = getMats1()[0];
9
+
10
+ // Same start and end (inclAllIfEqual=true): returns all nodes on the loop
11
+ const all = getAllBetween(cpNode, cpNode);
12
+ expect(all.cpNodes.length).toBe(getAllOnLoop(cpNode).length);
13
+ expect(all.cpNodes[0] === cpNode).toBe(true);
14
+
15
+ // Same start and end with inclAllIfEqual=false: returns empty
16
+ const none = getAllBetween(cpNode, cpNode, false);
17
+ expect(none.cpNodes.length).toBe(0);
18
+
19
+ // From cpNode to cpNode.next.next: returns [cpNode, cpNode.next]
20
+ const two = getAllBetween(cpNode, cpNode.next.next);
21
+ expect(two.cpNodes.length).toBe(2);
22
+ expect(two.cpNodes[0] === cpNode).toBe(true);
23
+ expect(two.cpNodes[1] === cpNode.next).toBe(true);
7
24
  });
@@ -1,5 +1,5 @@
1
1
  import { expect, test } from '@jest/globals';
2
- import { mats_obj1, getMats_calc1 } from './mat-dummys.js';
2
+ import { getMats1 } from '../../get-mats1.js';
3
3
  import { getAllOnCircle } from '../../../src/cp-node/fs/get-all-on-circle.js';
4
4
  import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
5
5
  import { isTerminating } from '../../../src/cp-node/fs/is-terminating.js';
@@ -12,7 +12,7 @@ test('CpNodeFs -> getAllOnCircle', function() {
12
12
  // expect(mats_obj1).toEqual(mats_calc1);
13
13
 
14
14
  // const { cpNode } = mats_calc1[0];
15
- const { cpNode } = mats_obj1[0];
15
+ const { cpNode } = getMats1()[0];
16
16
 
17
17
  const cpNode_ = cpNode.nextOnCircle;
18
18
 
@@ -1,7 +1,20 @@
1
1
  import { expect, test } from '@jest/globals';
2
2
  import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
3
+ import { getMats1 } from '../../get-mats1.js';
3
4
 
4
- test.skip('getAllOnLoop [STUB]', () => {
5
- // TODO: implement test
6
- expect(true).toBe(true);
5
+
6
+ test('getAllOnLoop', function() {
7
+ const { cpNode } = getMats1()[0];
8
+ const cpNodes = getAllOnLoop(cpNode);
9
+
10
+ expect(cpNodes.length).toBeGreaterThan(0);
11
+ expect(cpNodes[0] === cpNode).toBe(true);
12
+
13
+ // Each node's .next should point to the next node in the array (wrapping)
14
+ for (let i = 0; i < cpNodes.length; i++) {
15
+ expect(cpNodes[i].next === cpNodes[(i + 1) % cpNodes.length]).toBe(true);
16
+ }
17
+
18
+ // Starting from cpNode.next should give the same count
19
+ expect(getAllOnLoop(cpNode.next).length).toBe(cpNodes.length);
7
20
  });
@@ -1,7 +1,18 @@
1
1
  import { expect, test } from '@jest/globals';
2
2
  import { getAllVertices } from '../../../src/cp-node/fs/get-all-vertices.js';
3
+ import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
4
+ import { getMats1 } from '../../get-mats1.js';
3
5
 
4
- test.skip('getAllVertices [STUB]', () => {
5
- // TODO: implement test
6
- expect(true).toBe(true);
6
+
7
+ test('getAllVertices', function() {
8
+ const { cpNode } = getMats1()[0];
9
+ const vertices = getAllVertices(cpNode);
10
+
11
+ expect(vertices.length).toBeGreaterThan(0);
12
+
13
+ // All returned vertices should be on the loop
14
+ const loopSet = new Set(getAllOnLoop(cpNode));
15
+ for (const v of vertices) {
16
+ expect(loopSet.has(v)).toBe(true);
17
+ }
7
18
  });
@@ -1,7 +1,22 @@
1
1
  import { expect, test } from '@jest/globals';
2
2
  import { getChildren } from '../../../src/cp-node/fs/get-children.js';
3
+ import { isTerminating } from '../../../src/cp-node/fs/is-terminating.js';
4
+ import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
5
+ import { getMats1 } from '../../get-mats1.js';
3
6
 
4
- test.skip('getChildren [STUB]', () => {
5
- // TODO: implement test
6
- expect(true).toBe(true);
7
+
8
+ test('getChildren', function() {
9
+ const { cpNode } = getMats1()[0];
10
+ const allOnLoop = getAllOnLoop(cpNode);
11
+
12
+ const nonTerminating = allOnLoop.find(n => !isTerminating(n));
13
+ expect(nonTerminating).toBeDefined();
14
+
15
+ const children = getChildren(nonTerminating!);
16
+ expect(children.length).toBeGreaterThan(0);
17
+
18
+ for (const child of children) {
19
+ expect(child.next).toBeDefined();
20
+ expect(child.prev).toBeDefined();
21
+ }
7
22
  });
@@ -1,7 +1,18 @@
1
1
  import { expect, test } from '@jest/globals';
2
2
  import { getNonTerminatingOnCircle } from '../../../src/cp-node/fs/get-non-terminating-on-circle.js';
3
+ import { isTerminating } from '../../../src/cp-node/fs/is-terminating.js';
4
+ import { getMats1 } from '../../get-mats1.js';
3
5
 
4
- test.skip('getNonTerminatingOnCircle [STUB]', () => {
5
- // TODO: implement test
6
- expect(true).toBe(true);
6
+
7
+ test('getNonTerminatingOnCircle', function() {
8
+ const { cpNode } = getMats1()[0];
9
+
10
+ const nonTerm = getNonTerminatingOnCircle(cpNode);
11
+ for (const n of nonTerm) {
12
+ expect(isTerminating(n)).toBe(false);
13
+ }
14
+
15
+ // exclThis=true should not include cpNode itself
16
+ const nonTermExcl = getNonTerminatingOnCircle(cpNode, true);
17
+ expect(nonTermExcl.includes(cpNode)).toBe(false);
7
18
  });
@@ -1,7 +1,20 @@
1
1
  import { expect, test } from '@jest/globals';
2
2
  import { getProngCount } from '../../../src/cp-node/fs/get-prong-count.js';
3
+ import { getMats1 } from '../../get-mats1.js';
3
4
 
4
- test.skip('getProngCount [STUB]', () => {
5
- // TODO: implement test
6
- expect(true).toBe(true);
5
+
6
+ test('getProngCount', function() {
7
+ const { cpNode } = getMats1()[0];
8
+
9
+ const count = getProngCount(cpNode);
10
+ expect(count).toBeGreaterThanOrEqual(2);
11
+
12
+ // Manually counting nextOnCircle traversal should match
13
+ let circleCount = 0;
14
+ let curr = cpNode;
15
+ do {
16
+ circleCount++;
17
+ curr = curr.nextOnCircle;
18
+ } while (curr !== cpNode);
19
+ expect(circleCount).toBe(count);
7
20
  });
@@ -1,7 +1,15 @@
1
1
  import { expect, test } from '@jest/globals';
2
2
  import { getRealProngCount } from '../../../src/cp-node/fs/get-real-prong-count.js';
3
+ import { getProngCount } from '../../../src/cp-node/fs/get-prong-count.js';
4
+ import { getMats1 } from '../../get-mats1.js';
3
5
 
4
- test.skip('getRealProngCount [STUB]', () => {
5
- // TODO: implement test
6
- expect(true).toBe(true);
6
+
7
+ test('getRealProngCount', function() {
8
+ const { cpNode } = getMats1()[0];
9
+
10
+ const realCount = getRealProngCount(cpNode);
11
+ expect(realCount).toBeGreaterThanOrEqual(1);
12
+
13
+ // Real count excludes terminating nodes, so it's <= total prong count
14
+ expect(realCount).toBeLessThanOrEqual(getProngCount(cpNode));
7
15
  });
@@ -1,7 +1,24 @@
1
1
  import { expect, test } from '@jest/globals';
2
2
  import { getTerminatingOnCircle } from '../../../src/cp-node/fs/get-terminating-on-circle.js';
3
+ import { getNonTerminatingOnCircle } from '../../../src/cp-node/fs/get-non-terminating-on-circle.js';
4
+ import { getProngCount } from '../../../src/cp-node/fs/get-prong-count.js';
5
+ import { isTerminating } from '../../../src/cp-node/fs/is-terminating.js';
6
+ import { getMats1 } from '../../get-mats1.js';
3
7
 
4
- test.skip('getTerminatingOnCircle [STUB]', () => {
5
- // TODO: implement test
6
- expect(true).toBe(true);
8
+
9
+ test('getTerminatingOnCircle', function() {
10
+ const { cpNode } = getMats1()[0];
11
+
12
+ const terminating = getTerminatingOnCircle(cpNode);
13
+ for (const n of terminating) {
14
+ expect(isTerminating(n)).toBe(true);
15
+ }
16
+
17
+ // terminating + non-terminating = total prong count
18
+ const nonTerminating = getNonTerminatingOnCircle(cpNode);
19
+ expect(terminating.length + nonTerminating.length).toBe(getProngCount(cpNode));
20
+
21
+ // exclThis: cpNode should not be included
22
+ const termExcl = getTerminatingOnCircle(cpNode, true);
23
+ expect(termExcl.includes(cpNode)).toBe(false);
7
24
  });
@@ -1,7 +1,20 @@
1
1
  import { expect, test } from '@jest/globals';
2
2
  import { isFullyTerminating } from '../../../src/cp-node/fs/is-fully-terminating.js';
3
+ import { isTerminating } from '../../../src/cp-node/fs/is-terminating.js';
4
+ import { getAllOnCircle } from '../../../src/cp-node/fs/get-all-on-circle.js';
5
+ import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
6
+ import { getMats1 } from '../../get-mats1.js';
3
7
 
4
- test.skip('isFullyTerminating [STUB]', () => {
5
- // TODO: implement test
6
- expect(true).toBe(true);
8
+
9
+ test('isFullyTerminating', function() {
10
+ const { cpNode } = getMats1()[0];
11
+ const allOnLoop = getAllOnLoop(cpNode);
12
+
13
+ for (const n of allOnLoop) {
14
+ if (isFullyTerminating(n)) {
15
+ // All on the prevOnCircle's circle (excluding itself) should be terminating
16
+ const otherOnCircle = getAllOnCircle(n.prevOnCircle, true);
17
+ expect(otherOnCircle.every(isTerminating)).toBe(true);
18
+ }
19
+ }
7
20
  });
@@ -1,7 +1,24 @@
1
1
  import { expect, test } from '@jest/globals';
2
2
  import { isOnSameCircle } from '../../../src/cp-node/fs/is-on-same-circle.js';
3
+ import { getMats1 } from '../../get-mats1.js';
3
4
 
4
- test.skip('isOnSameCircle [STUB]', () => {
5
- // TODO: implement test
6
- expect(true).toBe(true);
5
+
6
+ test('isOnSameCircle', function() {
7
+ const { cpNode } = getMats1()[0];
8
+
9
+ // A node is on the same circle as itself
10
+ expect(isOnSameCircle(cpNode, cpNode)).toBe(true);
11
+
12
+ // A node is on the same circle as nextOnCircle
13
+ expect(isOnSameCircle(cpNode, cpNode.nextOnCircle)).toBe(true);
14
+
15
+ // Symmetric
16
+ expect(isOnSameCircle(cpNode.nextOnCircle, cpNode)).toBe(true);
17
+
18
+ // All nodes reachable via nextOnCircle are on the same circle
19
+ let curr = cpNode.nextOnCircle;
20
+ while (curr !== cpNode) {
21
+ expect(isOnSameCircle(cpNode, curr)).toBe(true);
22
+ curr = curr.nextOnCircle;
23
+ }
7
24
  });
@@ -1,7 +1,20 @@
1
1
  import { expect, test } from '@jest/globals';
2
2
  import { isOneProng } from '../../../src/cp-node/fs/is-one-prong.js';
3
+ import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
4
+ import { getMats1 } from '../../get-mats1.js';
3
5
 
4
- test.skip('isOneProng [STUB]', () => {
5
- // TODO: implement test
6
- expect(true).toBe(true);
6
+
7
+ test('isOneProng', function() {
8
+ const { cpNode } = getMats1()[0];
9
+ const allOnLoop = getAllOnLoop(cpNode);
10
+
11
+ for (const n of allOnLoop) {
12
+ if (isOneProng(n)) {
13
+ // One-prong: nextOnCircle is at the same position
14
+ const p1 = n.cp.pointOnShape.p;
15
+ const p2 = n.nextOnCircle.cp.pointOnShape.p;
16
+ expect(p1[0]).toBe(p2[0]);
17
+ expect(p1[1]).toBe(p2[1]);
18
+ }
19
+ }
7
20
  });
@@ -1,7 +1,14 @@
1
1
  import { expect, test } from '@jest/globals';
2
2
  import { isSharp } from '../../../src/cp-node/fs/is-sharp.js';
3
+ import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
4
+ import { getMats1 } from '../../get-mats1.js';
3
5
 
4
- test.skip('isSharp [STUB]', () => {
5
- // TODO: implement test
6
- expect(true).toBe(true);
6
+
7
+ test('isSharp', function() {
8
+ const { cpNode } = getMats1()[0];
9
+ const allOnLoop = getAllOnLoop(cpNode);
10
+
11
+ for (const n of allOnLoop) {
12
+ expect(isSharp(n)).toBe(n.cp.circle.radius === 0);
13
+ }
7
14
  });
@@ -1,7 +1,17 @@
1
1
  import { expect, test } from '@jest/globals';
2
2
  import { isSingle3Prong } from '../../../src/cp-node/fs/is-single-3-prong.js';
3
+ import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
4
+ import { getMats1 } from '../../get-mats1.js';
3
5
 
4
- test.skip('isSingle3Prong [STUB]', () => {
5
- // TODO: implement test
6
- expect(true).toBe(true);
6
+
7
+ test('isSingle3Prong', function() {
8
+ const { cpNode } = getMats1()[0];
9
+ const allOnLoop = getAllOnLoop(cpNode);
10
+
11
+ for (const n of allOnLoop) {
12
+ if (isSingle3Prong(n)) {
13
+ expect(n.next === n.nextOnCircle).toBe(true);
14
+ expect(n.next.next === n.next.nextOnCircle).toBe(true);
15
+ }
16
+ }
7
17
  });
@@ -1,7 +1,16 @@
1
1
  import { expect, test } from '@jest/globals';
2
2
  import { isSpecial } from '../../../src/cp-node/fs/is-special.js';
3
+ import { getRealProngCount } from '../../../src/cp-node/fs/get-real-prong-count.js';
4
+ import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
5
+ import { getMats1 } from '../../get-mats1.js';
3
6
 
4
- test.skip('isSpecial [STUB]', () => {
5
- // TODO: implement test
6
- expect(true).toBe(true);
7
+
8
+ test('isSpecial', function() {
9
+ const { cpNode } = getMats1()[0];
10
+ const allOnLoop = getAllOnLoop(cpNode);
11
+
12
+ for (const n of allOnLoop) {
13
+ const expected = getRealProngCount(n) !== 2 && !n.isHoleClosing;
14
+ expect(isSpecial(n)).toBe(expected);
15
+ }
7
16
  });
@@ -1,7 +1,19 @@
1
1
  import { expect, test } from '@jest/globals';
2
2
  import { isTerminating } from '../../../src/cp-node/fs/is-terminating.js';
3
+ import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
4
+ import { getMats1 } from '../../get-mats1.js';
3
5
 
4
- test.skip('isTerminating [STUB]', () => {
5
- // TODO: implement test
6
- expect(true).toBe(true);
6
+
7
+ test('isTerminating', function() {
8
+ const { cpNode } = getMats1()[0];
9
+ const allOnLoop = getAllOnLoop(cpNode);
10
+
11
+ // A non-trivial MAT should have at least one terminating node
12
+ const termCount = allOnLoop.filter(isTerminating).length;
13
+ expect(termCount).toBeGreaterThan(0);
14
+
15
+ // Verify the definition: cpNode === cpNode.next.prevOnCircle
16
+ for (const n of allOnLoop) {
17
+ expect(isTerminating(n)).toBe(n === n.next.prevOnCircle);
18
+ }
7
19
  });
@@ -1,7 +1,17 @@
1
1
  import { expect, test } from '@jest/globals';
2
2
  import { isTrivial } from '../../../src/cp-node/fs/is-trivial.js';
3
+ import { isTerminating } from '../../../src/cp-node/fs/is-terminating.js';
4
+ import { getAllOnCircle } from '../../../src/cp-node/fs/get-all-on-circle.js';
5
+ import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
6
+ import { getMats1 } from '../../get-mats1.js';
3
7
 
4
- test.skip('isTrivial [STUB]', () => {
5
- // TODO: implement test
6
- expect(true).toBe(true);
8
+
9
+ test('isTrivial', function() {
10
+ const { cpNode } = getMats1()[0];
11
+ const allOnLoop = getAllOnLoop(cpNode);
12
+
13
+ for (const n of allOnLoop) {
14
+ const expected = getAllOnCircle(n).every(isTerminating);
15
+ expect(isTrivial(n)).toBe(expected);
16
+ }
7
17
  });
@@ -1,7 +1,15 @@
1
1
  import { expect, test } from '@jest/globals';
2
2
  import { isTwoProng } from '../../../src/cp-node/fs/is-two-prong.js';
3
+ import { getRealProngCount } from '../../../src/cp-node/fs/get-real-prong-count.js';
4
+ import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
5
+ import { getMats1 } from '../../get-mats1.js';
3
6
 
4
- test.skip('isTwoProng [STUB]', () => {
5
- // TODO: implement test
6
- expect(true).toBe(true);
7
+
8
+ test('isTwoProng', function() {
9
+ const { cpNode } = getMats1()[0];
10
+ const allOnLoop = getAllOnLoop(cpNode);
11
+
12
+ for (const n of allOnLoop) {
13
+ expect(isTwoProng(n)).toBe(getRealProngCount(n) === 2);
14
+ }
7
15
  });
@@ -1,7 +1,17 @@
1
1
  import { expect, test } from '@jest/globals';
2
2
  import { isVertexSpecial } from '../../../src/cp-node/fs/is-vertex-special.js';
3
+ import { isVertex } from '../../../src/cp-node/fs/is-vertex.js';
4
+ import { isSpecial } from '../../../src/cp-node/fs/is-special.js';
5
+ import { getAllOnLoop } from '../../../src/cp-node/fs/get-all-on-loop.js';
6
+ import { getMats1 } from '../../get-mats1.js';
3
7
 
4
- test.skip('isVertexSpecial [STUB]', () => {
5
- // TODO: implement test
6
- expect(true).toBe(true);
8
+
9
+ test('isVertexSpecial', function() {
10
+ const { cpNode } = getMats1()[0];
11
+ const allOnLoop = getAllOnLoop(cpNode);
12
+
13
+ // isVertexSpecial === isVertex(isSpecial)
14
+ for (const n of allOnLoop) {
15
+ expect(isVertexSpecial(n)).toBe(isVertex(isSpecial)(n));
16
+ }
7
17
  });