@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.
- package/components/SolverDebugger3d.tsx +2 -2
- package/dist/index.d.ts +23 -3
- package/dist/index.js +236 -60
- package/lib/RectDiffPipeline.ts +62 -22
- package/lib/fixtures/twoNodeExpansionFixture.ts +10 -2
- package/lib/rectdiff-visualization.ts +2 -1
- package/lib/solvers/RectDiffExpansionSolver/RectDiffExpansionSolver.ts +8 -3
- package/lib/solvers/RectDiffGridSolverPipeline/RectDiffGridSolverPipeline.ts +48 -9
- package/lib/solvers/RectDiffGridSolverPipeline/buildObstacleIndexes.ts +14 -6
- package/lib/solvers/RectDiffSeedingSolver/RectDiffSeedingSolver.ts +41 -5
- package/lib/solvers/RectDiffSeedingSolver/computeInverseRects.ts +37 -1
- package/lib/solvers/RectDiffSeedingSolver/layers.ts +9 -5
- package/lib/utils/expandRectFromSeed.ts +11 -5
- package/lib/utils/finalizeRects.ts +17 -9
- package/lib/utils/padRect.ts +11 -0
- package/lib/utils/renderObstacleClearance.ts +50 -0
- package/package.json +1 -1
- package/pages/bugreport11.page.tsx +1 -0
- package/test-assets/bugreport-c7537683-stalling.json +1107 -0
- package/tests/board-outline.test.ts +1 -1
- package/tests/bugreport-stalling.test.ts +102 -0
- package/tests/fixtures/makeSimpleRouteOutlineGraphics.ts +5 -1
- package/tests/should-expand-node.test.ts +9 -1
- package/tests/solver/__snapshots__/rectDiffGridSolverPipeline.snap.svg +2 -2
- package/tests/solver/bugreport11-b2de3c/__snapshots__/bugreport11-b2de3c-clearance.snap.svg +44 -0
- package/tests/solver/bugreport11-b2de3c/__snapshots__/bugreport11-b2de3c.snap.svg +2 -2
- package/tests/solver/bugreport11-b2de3c/bugreport11-b2de3c-clearance.test.ts +97 -0
- package/tests/solver/bugreport26-66b0b2/__snapshots__/bugreport26-66b0b2.snap.svg +2 -2
- package/tests/solver/bugreport27-dd3734/__snapshots__/bugreport27-dd3734.snap.svg +2 -2
- package/tests/solver/bugreport28-18a9ef/__snapshots__/bugreport28-18a9ef.snap.svg +2 -2
- package/tests/solver/bugreport29-7deae8/__snapshots__/bugreport29-7deae8.snap.svg +2 -2
- package/tests/solver/bugreport30-2174c8/__snapshots__/bugreport30-2174c8.snap.svg +2 -2
- package/tests/solver/bugreport33-213d45/__snapshots__/bugreport33-213d45.snap.svg +2 -2
- package/tests/solver/bugreport34-e9dea2/__snapshots__/bugreport34-e9dea2.snap.svg +2 -2
- package/tests/solver/bugreport35-191db9/__snapshots__/bugreport35-191db9.snap.svg +2 -2
- 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
|
|
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:
|
|
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(
|
|
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
|
{
|