@tscircuit/rectdiff 0.0.21 → 0.0.23

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 (36) hide show
  1. package/components/SolverDebugger3d.tsx +2 -2
  2. package/dist/index.d.ts +23 -3
  3. package/dist/index.js +236 -60
  4. package/lib/RectDiffPipeline.ts +62 -22
  5. package/lib/fixtures/twoNodeExpansionFixture.ts +10 -2
  6. package/lib/rectdiff-visualization.ts +2 -1
  7. package/lib/solvers/RectDiffExpansionSolver/RectDiffExpansionSolver.ts +8 -3
  8. package/lib/solvers/RectDiffGridSolverPipeline/RectDiffGridSolverPipeline.ts +48 -9
  9. package/lib/solvers/RectDiffGridSolverPipeline/buildObstacleIndexes.ts +14 -6
  10. package/lib/solvers/RectDiffSeedingSolver/RectDiffSeedingSolver.ts +41 -5
  11. package/lib/solvers/RectDiffSeedingSolver/computeInverseRects.ts +37 -1
  12. package/lib/solvers/RectDiffSeedingSolver/layers.ts +9 -5
  13. package/lib/utils/expandRectFromSeed.ts +11 -5
  14. package/lib/utils/finalizeRects.ts +17 -9
  15. package/lib/utils/padRect.ts +11 -0
  16. package/lib/utils/renderObstacleClearance.ts +50 -0
  17. package/package.json +1 -1
  18. package/pages/bugreport11.page.tsx +1 -0
  19. package/test-assets/bugreport-c7537683-stalling.json +1107 -0
  20. package/tests/board-outline.test.ts +1 -1
  21. package/tests/bugreport-stalling.test.ts +102 -0
  22. package/tests/fixtures/makeSimpleRouteOutlineGraphics.ts +5 -1
  23. package/tests/should-expand-node.test.ts +9 -1
  24. package/tests/solver/__snapshots__/rectDiffGridSolverPipeline.snap.svg +2 -2
  25. package/tests/solver/bugreport11-b2de3c/__snapshots__/bugreport11-b2de3c-clearance.snap.svg +44 -0
  26. package/tests/solver/bugreport11-b2de3c/__snapshots__/bugreport11-b2de3c.snap.svg +2 -2
  27. package/tests/solver/bugreport11-b2de3c/bugreport11-b2de3c-clearance.test.ts +97 -0
  28. package/tests/solver/bugreport26-66b0b2/__snapshots__/bugreport26-66b0b2.snap.svg +2 -2
  29. package/tests/solver/bugreport27-dd3734/__snapshots__/bugreport27-dd3734.snap.svg +2 -2
  30. package/tests/solver/bugreport28-18a9ef/__snapshots__/bugreport28-18a9ef.snap.svg +2 -2
  31. package/tests/solver/bugreport29-7deae8/__snapshots__/bugreport29-7deae8.snap.svg +2 -2
  32. package/tests/solver/bugreport30-2174c8/__snapshots__/bugreport30-2174c8.snap.svg +2 -2
  33. package/tests/solver/bugreport33-213d45/__snapshots__/bugreport33-213d45.snap.svg +2 -2
  34. package/tests/solver/bugreport34-e9dea2/__snapshots__/bugreport34-e9dea2.snap.svg +2 -2
  35. package/tests/solver/bugreport35-191db9/__snapshots__/bugreport35-191db9.snap.svg +2 -2
  36. package/tests/solver/bugreport36-bf8303/__snapshots__/bugreport36-bf8303.snap.svg +1 -1
@@ -6,7 +6,7 @@ import { makeCapacityMeshNodeWithLayerInfo } from "./fixtures/makeCapacityMeshNo
6
6
 
7
7
  test("board outline snapshot", async () => {
8
8
  const solver = new RectDiffPipeline({
9
- simpleRouteJson: boardWithCutout as any,
9
+ simpleRouteJson: boardWithCutout,
10
10
  })
11
11
 
12
12
  // Run to completion
@@ -0,0 +1,102 @@
1
+ import { expect, test } from "bun:test"
2
+ import { RectDiffPipeline } from "../lib/RectDiffPipeline"
3
+ import stallingBugReport from "../test-assets/bugreport-c7537683-stalling.json"
4
+ import type { SimpleRouteJson } from "../lib/types/srj-types"
5
+
6
+ /**
7
+ * Bug #518: RectDiff Stalling Issue
8
+ *
9
+ * The expandRectFromSeed() function had an unbounded while (improved) loop
10
+ * with no max iteration guard. Combined with floating-point precision
11
+ * mismatches from mixed precision coordinates (4 decimals like -2.4625
12
+ * mixed with 14+ decimals like 34.09920366859815), this could cause infinite
13
+ * looping where expansions would succeed by infinitesimal amounts.
14
+ *
15
+ * Fix: Added MAX_ITERATIONS guard (1000) and MIN_EXPANSION threshold (1e-6)
16
+ * to the expansion loop.
17
+ */
18
+ test("Bug #518: RectDiff solver completes without stalling on mixed-precision coordinates", () => {
19
+ const simpleRouteJson = stallingBugReport as SimpleRouteJson
20
+
21
+ const pipeline = new RectDiffPipeline({ simpleRouteJson })
22
+
23
+ // Setup initializes state
24
+ pipeline.setup()
25
+ expect(pipeline.solved).toBe(false)
26
+
27
+ // Step advances one candidate at a time
28
+ // This test ensures the solver completes within a reasonable number of steps
29
+ let stepCount = 0
30
+ const maxSteps = 10000 // safety limit
31
+
32
+ while (!pipeline.solved && stepCount < maxSteps) {
33
+ pipeline.step()
34
+ stepCount++
35
+ }
36
+
37
+ expect(pipeline.solved).toBe(true)
38
+ expect(stepCount).toBeLessThan(maxSteps)
39
+
40
+ const output = pipeline.getOutput()
41
+ expect(output.meshNodes.length).toBeGreaterThan(0)
42
+
43
+ // Verify mesh nodes have valid dimensions
44
+ for (const node of output.meshNodes) {
45
+ expect(node.width).toBeGreaterThan(0)
46
+ expect(node.height).toBeGreaterThan(0)
47
+ }
48
+ })
49
+
50
+ test("Bug #518: expandRectFromSeed iteration guard prevents infinite loops", () => {
51
+ // Test with a simple case that would complete quickly
52
+ // This validates the iteration guard doesn't break normal operation
53
+ const simpleRouteJson: SimpleRouteJson = {
54
+ bounds: {
55
+ minX: 0,
56
+ maxX: 10,
57
+ minY: 0,
58
+ maxY: 10,
59
+ },
60
+ obstacles: [
61
+ // Create tightly-packed obstacles similar to QFP pads
62
+ // with mixed precision to simulate the bug conditions
63
+ {
64
+ type: "rect",
65
+ layers: ["top"],
66
+ center: { x: 2.4625, y: 2.5 }, // 4 decimal places
67
+ width: 0.5,
68
+ height: 0.25,
69
+ connectedTo: [],
70
+ },
71
+ {
72
+ type: "rect",
73
+ layers: ["top"],
74
+ center: { x: 2.4625, y: 3.0 },
75
+ width: 0.5,
76
+ height: 0.25,
77
+ connectedTo: [],
78
+ },
79
+ {
80
+ type: "rect",
81
+ layers: ["top"],
82
+ center: { x: 2.4625, y: 3.5 },
83
+ width: 0.5,
84
+ height: 0.25,
85
+ connectedTo: [],
86
+ },
87
+ ],
88
+ connections: [],
89
+ layerCount: 2,
90
+ minTraceWidth: 0.15,
91
+ }
92
+
93
+ const pipeline = new RectDiffPipeline({ simpleRouteJson })
94
+
95
+ // Should complete without hanging
96
+ pipeline.solve()
97
+
98
+ expect(pipeline.solved).toBe(true)
99
+
100
+ const output = pipeline.getOutput()
101
+ expect(output.meshNodes.length).toBeGreaterThan(0)
102
+ })
@@ -1,11 +1,15 @@
1
1
  import type { GraphicsObject, Line } from "graphics-debug"
2
2
  import type { SimpleRouteJson } from "lib/types/srj-types"
3
+ export type SimpleRouteOutlineInput = {
4
+ bounds: SimpleRouteJson["bounds"]
5
+ outline?: SimpleRouteJson["outline"]
6
+ }
3
7
 
4
8
  /**
5
9
  * Creates a GraphicsObject that draws the SRJ outline (or bounds fallback).
6
10
  */
7
11
  export const makeSimpleRouteOutlineGraphics = (
8
- srj: SimpleRouteJson,
12
+ srj: SimpleRouteOutlineInput,
9
13
  ): GraphicsObject => {
10
14
  const lines: NonNullable<Line[]> = []
11
15
 
@@ -15,7 +15,15 @@ test("RectDiff expansion reproduces the two-node gap fixture", async () => {
15
15
  expect(meshNodes.length).toBeGreaterThanOrEqual(2)
16
16
 
17
17
  const finalGraphics = makeCapacityMeshNodeWithLayerInfo(meshNodes)
18
- const outline = makeSimpleRouteOutlineGraphics(input.srj)
18
+ const outline = makeSimpleRouteOutlineGraphics({
19
+ bounds: {
20
+ minX: input.bounds.x,
21
+ maxX: input.bounds.x + input.bounds.width,
22
+ minY: input.bounds.y,
23
+ maxY: input.bounds.y + input.bounds.height,
24
+ },
25
+ outline: undefined,
26
+ })
19
27
  const svg = getSvgFromGraphicsObject(
20
28
  mergeGraphics({ rects: finalGraphics.values().toArray().flat() }, outline),
21
29
  {