@tscircuit/schematic-trace-solver 0.0.187 → 0.0.189
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/dist/index.d.ts +42 -23
- package/dist/index.js +1053 -316
- package/lib/solvers/InlineNetLabelSolver/InlineNetLabelSolver.ts +612 -230
- package/lib/solvers/InlineNetLabelSolver/alignPortOnlyInlineNetLabelStubs.ts +2 -6
- package/lib/solvers/InlineNetLabelSolver/getAnchoredNetLabelRenderedBounds.ts +13 -0
- package/lib/solvers/InlineNetLabelSolver/getInlineLabelObstacles.ts +64 -0
- package/lib/solvers/InlineNetLabelSolver/getLocalTraceLabelShifts.ts +407 -0
- package/lib/solvers/InlineNetLabelSolver/getOutputLabelCollisions.ts +145 -0
- package/lib/solvers/InlineNetLabelSolver/isLabelRepresentedInline.ts +15 -0
- package/lib/solvers/InlineNetLabelSolver/pushAnchoredNetLabelsAwayFromInlineLabels.ts +61 -31
- package/lib/solvers/NetLabelNetLabelCollisionSolver/NetLabelNetLabelCollisionSolver.ts +94 -16
- package/lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts +4 -3
- package/lib/solvers/SameNetJunctionAlignmentSolver/alignSameNetJunctions.ts +7 -7
- package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +3 -0
- package/lib/solvers/TraceCleanupSolver/sub-solver/generateLShapeRerouteCandidates.ts +5 -1
- package/lib/types/InputProblem.ts +2 -2
- package/package.json +1 -1
- package/site/SchematicTracePipelineSolver/repro-robot-controller-imu-tof.page.tsx +7 -0
- package/site/bug-reports/bug-report-20260907T110144Z.page.tsx +4 -0
- package/site/bug-reports/bug-report-20260907T145640Z.page.tsx +4 -0
- package/tests/bug-reports/bug-report-20260730T061837Z/__snapshots__/bug-report-20260730T061837Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260806T093501Z/__snapshots__/bug-report-20260806T093501Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260811T075142Z/__snapshots__/bug-report-20260811T075142Z.snap.svg +18 -18
- package/tests/bug-reports/bug-report-20260819T091818Z/__snapshots__/bug-report-20260819T091818Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260819T091818Z/bug-report-20260819T091818Z.test.ts +21 -0
- package/tests/bug-reports/bug-report-20260825T103621Z/__snapshots__/bug-report-20260825T103621Z.snap.svg +5 -38
- package/tests/bug-reports/bug-report-20260826T072956Z/__snapshots__/bug-report-20260826T072956Z.snap.svg +3 -9
- package/tests/bug-reports/bug-report-20260901T055358Z/__snapshots__/bug-report-20260901T055358Z.snap.svg +18 -30
- package/tests/bug-reports/bug-report-20260901T055358Z/bug-report-20260901T055358Z.test.ts +33 -0
- package/tests/bug-reports/bug-report-20260907T110144Z/__snapshots__/bug-report-20260907T110144Z.snap.svg +282 -0
- package/tests/bug-reports/bug-report-20260907T110144Z/bug-report-20260907T110144Z.json +1073 -0
- package/tests/bug-reports/bug-report-20260907T110144Z/bug-report-20260907T110144Z.test.ts +12 -0
- package/tests/bug-reports/bug-report-20260907T145640Z/__snapshots__/bug-report-20260907T145640Z.snap.svg +1107 -0
- package/tests/bug-reports/bug-report-20260907T145640Z/bug-report-20260907T145640Z.json +3563 -0
- package/tests/bug-reports/bug-report-20260907T145640Z/bug-report-20260907T145640Z.test.ts +117 -0
- package/tests/repros/__snapshots__/repro-battery-management-bq24073.snap.svg +4 -4
- package/tests/repros/__snapshots__/repro-board-648-esp12f-section.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-core-tb67s579ftg-inline-label-routing.snap.svg +20 -20
- package/tests/repros/__snapshots__/repro-esp12f-section.snap.svg +37 -55
- package/tests/repros/__snapshots__/repro-hub-usb-sheet.snap.svg +44 -68
- package/tests/repros/__snapshots__/repro-mspm0l1306-capacitor-symmetry.snap.svg +3 -9
- package/tests/repros/__snapshots__/repro-robot-controller-imu-tof.snap.svg +199 -0
- package/tests/repros/__snapshots__/repro-robot-controller-imu-tof.source.svg +33 -0
- package/tests/repros/__snapshots__/repro-usb-power-vbus-label-detour.snap.svg +50 -74
- package/tests/repros/__snapshots__/repro48-555-timer-vcc-rail-label.snap.svg +2 -2
- package/tests/repros/__snapshots__/rp2040-robot-controller-disconnected-gnd.snap.svg +103 -0
- package/tests/repros/assets/repro-robot-controller-imu-tof.input.json +540 -0
- package/tests/repros/assets/rp2040-robot-controller.input.json +349 -0
- package/tests/repros/repro-battery-management-bq24073.test.ts +13 -1
- package/tests/repros/repro-hub-usb-sheet.test.ts +25 -0
- package/tests/repros/repro-robot-controller-imu-tof.test.ts +83 -0
- package/tests/repros/repro-usb-power-vbus-label-detour.test.ts +59 -13
- package/tests/repros/rp2040-robot-controller-disconnected-gnd.test.ts +59 -0
- package/tests/solvers/InlineNetLabelSolver/get-anchored-net-label-rendered-bounds.test.ts +24 -0
- package/tests/solvers/InlineNetLabelSolver/local-trace-label-shifts.test.ts +296 -0
- package/tests/solvers/InlineNetLabelSolver/multi-pin-connected-components.test.ts +7 -4
- package/tests/solvers/InlineNetLabelSolver/push-anchored-net-labels-away.test.ts +2 -1
- package/tests/solvers/InlineNetLabelSolver/shared-direct-and-named-connection.test.ts +62 -0
- package/tests/solvers/InlineNetLabelSolver/two-pin-terminal-stubs-atomic.test.ts +9 -3
- package/tests/solvers/TraceCleanupSolver/perpendicular-detours-preserve-endpoints.test.ts +60 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { getOutputLabelCollisions } from "lib/solvers/InlineNetLabelSolver/getOutputLabelCollisions"
|
|
2
|
+
import { doSegmentsIntersect } from "@tscircuit/math-utils/line-intersections"
|
|
3
|
+
import { expect, test } from "bun:test"
|
|
4
|
+
import { getAnchoredNetLabelRenderedBounds } from "lib/solvers/InlineNetLabelSolver/getAnchoredNetLabelRenderedBounds"
|
|
5
|
+
import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
|
|
6
|
+
import { simplifyPath } from "lib/solvers/TraceCleanupSolver/simplifyPath"
|
|
7
|
+
import { segmentIntersectsRect } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/collisions"
|
|
8
|
+
import inputProblem from "./bug-report-20260907T145640Z.json"
|
|
9
|
+
import "tests/fixtures/matcher"
|
|
10
|
+
|
|
11
|
+
test("bug-report-20260907T145640Z", async () => {
|
|
12
|
+
const original = structuredClone(inputProblem)
|
|
13
|
+
const solver = new SchematicTracePipelineSolver(inputProblem as any, {
|
|
14
|
+
hideRatsNet: true,
|
|
15
|
+
})
|
|
16
|
+
solver.solve()
|
|
17
|
+
expect(solver.solved).toBe(true)
|
|
18
|
+
expect(solver.failed).toBe(false)
|
|
19
|
+
// This is the output consumed by core, before NetLabelToTraceSolver renders
|
|
20
|
+
// diagnostic terminal wires.
|
|
21
|
+
const output = solver.inlineNetLabelSolver!.getOutput()
|
|
22
|
+
// Audit the entire report, including U3, rather than selected screenshots.
|
|
23
|
+
expect([...getOutputLabelCollisions(output)]).toEqual([])
|
|
24
|
+
for (const connection of inputProblem.netConnections.filter(
|
|
25
|
+
(connection) => connection.allowInlineNetLabel,
|
|
26
|
+
)) {
|
|
27
|
+
expect(
|
|
28
|
+
output.netLabelPlacements.filter(
|
|
29
|
+
(label) => label.netId === connection.netId,
|
|
30
|
+
),
|
|
31
|
+
).toEqual([])
|
|
32
|
+
for (const pinId of connection.pinIds)
|
|
33
|
+
expect(
|
|
34
|
+
output.inlineNetLabelPlacements.filter(
|
|
35
|
+
(label) =>
|
|
36
|
+
label.netId === connection.netId && label.pinIds.includes(pinId),
|
|
37
|
+
),
|
|
38
|
+
).toHaveLength(1)
|
|
39
|
+
}
|
|
40
|
+
// Remote routes must clear entire terminal wires, including their tails
|
|
41
|
+
// beyond the text and terminals on the same net (the U3 SCL regression).
|
|
42
|
+
const terminalWireCrossings = output.inlineNetLabelPlacements.flatMap(
|
|
43
|
+
(label) => {
|
|
44
|
+
if (!label.stubTracePath) return []
|
|
45
|
+
const [start, end] = label.stubTracePath
|
|
46
|
+
return output.traces
|
|
47
|
+
.filter(
|
|
48
|
+
(trace) =>
|
|
49
|
+
!trace.pinIds.some((pinId) => label.pinIds.includes(pinId)) &&
|
|
50
|
+
trace.tracePath
|
|
51
|
+
.slice(1)
|
|
52
|
+
.some((point, index) =>
|
|
53
|
+
doSegmentsIntersect(
|
|
54
|
+
start!,
|
|
55
|
+
end!,
|
|
56
|
+
trace.tracePath[index]!,
|
|
57
|
+
point,
|
|
58
|
+
),
|
|
59
|
+
),
|
|
60
|
+
)
|
|
61
|
+
.map((trace) => ({ terminal: label.pinIds, trace: trace.mspPairId }))
|
|
62
|
+
},
|
|
63
|
+
)
|
|
64
|
+
expect(terminalWireCrossings).toEqual([])
|
|
65
|
+
// U2 pin 17 must remain connected and clear of the final signal labels.
|
|
66
|
+
const traceId = "schematic_port_57-schematic_port_86"
|
|
67
|
+
const clearedTrace = solver
|
|
68
|
+
.traceLabelOverlapAvoidanceSolver!.getOutput()
|
|
69
|
+
.traces.find((trace) => trace.mspPairId === traceId)!
|
|
70
|
+
const finalTrace = output.traces.find((trace) => trace.mspPairId === traceId)!
|
|
71
|
+
expect(finalTrace).toBeDefined()
|
|
72
|
+
expect(finalTrace.tracePath).toHaveLength(4)
|
|
73
|
+
const beforeInline = new Map(
|
|
74
|
+
solver
|
|
75
|
+
.inlineNetLabelSolver!.getConstructorParams()[0]
|
|
76
|
+
.traces.map((trace) => [trace.mspPairId, trace]),
|
|
77
|
+
)
|
|
78
|
+
for (const trace of output.traces) {
|
|
79
|
+
const before = beforeInline.get(trace.mspPairId)
|
|
80
|
+
if (before)
|
|
81
|
+
expect(simplifyPath(trace.tracePath).length).toBeLessThanOrEqual(
|
|
82
|
+
simplifyPath(before.tracePath).length,
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
expect(finalTrace.tracePath[0]).toEqual(clearedTrace.tracePath[0])
|
|
86
|
+
expect(finalTrace.tracePath.at(-1)).toEqual(clearedTrace.tracePath.at(-1))
|
|
87
|
+
for (const label of output.netLabelPlacements) {
|
|
88
|
+
if (label.globalConnNetId === finalTrace.globalConnNetId) continue
|
|
89
|
+
const bounds = getAnchoredNetLabelRenderedBounds(label)
|
|
90
|
+
expect(
|
|
91
|
+
finalTrace.tracePath
|
|
92
|
+
.slice(1)
|
|
93
|
+
.some((end, index) =>
|
|
94
|
+
segmentIntersectsRect(finalTrace.tracePath[index]!, end, bounds),
|
|
95
|
+
),
|
|
96
|
+
).toBe(false)
|
|
97
|
+
}
|
|
98
|
+
// Power labels in the supplied input are not opted in. Preserve them rather
|
|
99
|
+
// than overriding the caller's policy to make every label appear inline.
|
|
100
|
+
for (const netId of [
|
|
101
|
+
"PMID",
|
|
102
|
+
"OLED_3V",
|
|
103
|
+
"V3",
|
|
104
|
+
"PACK_P",
|
|
105
|
+
"GAUGE_VDD",
|
|
106
|
+
"BAT_SYS",
|
|
107
|
+
]) {
|
|
108
|
+
expect(
|
|
109
|
+
output.netLabelPlacements.some((label) => label.netId === netId),
|
|
110
|
+
).toBe(true)
|
|
111
|
+
expect(
|
|
112
|
+
output.inlineNetLabelPlacements.some((label) => label.netId === netId),
|
|
113
|
+
).toBe(false)
|
|
114
|
+
}
|
|
115
|
+
expect(inputProblem).toEqual(original)
|
|
116
|
+
await expect(solver).toMatchSolverSnapshot(import.meta.path)
|
|
117
|
+
})
|