@tscircuit/schematic-trace-solver 0.0.157 → 0.0.159
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 +1 -0
- package/dist/index.js +269 -58
- package/lib/solvers/LongDistancePairSolver/LongDistancePairSolver.ts +15 -8
- package/lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver.ts +5 -0
- package/lib/solvers/MspConnectionPairSolver/getGroundConnectionPolicy.ts +83 -0
- package/lib/solvers/SameNetJunctionAlignmentSolver/SameNetJunctionAlignmentSolver.ts +6 -1
- package/lib/solvers/SameNetJunctionAlignmentSolver/alignSameNetJunctions.ts +196 -67
- package/lib/solvers/SameNetJunctionAlignmentSolver/placeGroundRailLabelsAtOuterEnd.ts +122 -0
- package/package.json +1 -1
- package/site/bug-reports/bug-report-20260826T072956Z.page.tsx +4 -0
- package/tests/bug-reports/bug-report-20260706T213649Z/__snapshots__/bug-report-20260706T213649Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260706T220324Z/__snapshots__/bug-report-20260706T220324Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260707T020342Z/__snapshots__/bug-report-20260707T020342Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260707T092615Z/__snapshots__/bug-report-20260707T092615Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260707T134549Z/__snapshots__/bug-report-20260707T134549Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260707T134722Z/__snapshots__/bug-report-20260707T134722Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260707T140410Z/__snapshots__/bug-report-20260707T140410Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260707T141025Z/__snapshots__/bug-report-20260707T141025Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260707T141421Z/__snapshots__/bug-report-20260707T141421Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260707T230831Z/__snapshots__/bug-report-20260707T230831Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260708T053736Z/__snapshots__/bug-report-20260708T053736Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260708T055430Z/__snapshots__/bug-report-20260708T055430Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260708T095725Z/__snapshots__/bug-report-20260708T095725Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260716T144856Z/__snapshots__/bug-report-20260716T144856Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260717T022934Z/__snapshots__/bug-report-20260717T022934Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260717T031704Z/__snapshots__/bug-report-20260717T031704Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260717T042845Z/__snapshots__/bug-report-20260717T042845Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260721T221026Z/__snapshots__/bug-report-20260721T221026Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260724T175257Z/__snapshots__/bug-report-20260724T175257Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260728T144234Z/__snapshots__/bug-report-20260728T144234Z.snap.svg +4 -4
- package/tests/bug-reports/bug-report-20260728T225606Z/__snapshots__/bug-report-20260728T225606Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260730T061837Z/__snapshots__/bug-report-20260730T061837Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260731T052229Z/__snapshots__/bug-report-20260731T052229Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260804T095800Z/__snapshots__/bug-report-20260804T095800Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260804T171919Z/__snapshots__/bug-report-20260804T171919Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260804T225912Z/__snapshots__/bug-report-20260804T225912Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260805T061316Z/__snapshots__/bug-report-20260805T061316Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260806T061548Z/__snapshots__/bug-report-20260806T061548Z.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 +2 -2
- package/tests/bug-reports/bug-report-20260815T073240Z/__snapshots__/bug-report-20260815T073240Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260819T091818Z/__snapshots__/bug-report-20260819T091818Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260825T045913Z/__snapshots__/bug-report-20260825T045913Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260825T103621Z/__snapshots__/bug-report-20260825T103621Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260826T072956Z/__snapshots__/bug-report-20260826T072956Z.snap.svg +851 -0
- package/tests/bug-reports/bug-report-20260826T072956Z/bug-report-20260826T072956Z.json +2452 -0
- package/tests/bug-reports/bug-report-20260826T072956Z/bug-report-20260826T072956Z.test.ts +12 -0
- package/tests/examples/__snapshots__/example01.snap.svg +2 -2
- package/tests/examples/__snapshots__/example02.snap.svg +12 -12
- package/tests/examples/__snapshots__/example03.snap.svg +2 -2
- package/tests/examples/__snapshots__/example04.snap.svg +2 -2
- package/tests/examples/__snapshots__/example05.snap.svg +2 -2
- package/tests/examples/__snapshots__/example06.snap.svg +2 -2
- package/tests/examples/__snapshots__/example07.snap.svg +2 -2
- package/tests/examples/__snapshots__/example08.snap.svg +2 -2
- package/tests/examples/__snapshots__/example09.snap.svg +2 -2
- package/tests/examples/__snapshots__/example10.snap.svg +2 -2
- package/tests/examples/__snapshots__/example11.snap.svg +2 -2
- package/tests/examples/__snapshots__/example12.snap.svg +2 -2
- package/tests/examples/__snapshots__/example13.snap.svg +2 -2
- package/tests/examples/__snapshots__/example14.snap.svg +2 -2
- package/tests/examples/__snapshots__/example15.snap.svg +2 -2
- package/tests/examples/__snapshots__/example16.snap.svg +2 -2
- package/tests/examples/__snapshots__/example17.snap.svg +2 -2
- package/tests/examples/__snapshots__/example18.snap.svg +2 -2
- package/tests/examples/__snapshots__/example19.snap.svg +2 -2
- package/tests/examples/__snapshots__/example20.snap.svg +2 -2
- package/tests/examples/__snapshots__/example21.snap.svg +2 -2
- package/tests/examples/__snapshots__/example22.snap.svg +2 -2
- package/tests/examples/__snapshots__/example23.snap.svg +2 -2
- package/tests/examples/__snapshots__/example24.snap.svg +2 -2
- package/tests/examples/__snapshots__/example25.snap.svg +2 -2
- package/tests/examples/__snapshots__/example26.snap.svg +2 -2
- package/tests/examples/__snapshots__/example27.snap.svg +2 -2
- package/tests/examples/__snapshots__/example28.snap.svg +2 -2
- package/tests/examples/__snapshots__/example29.snap.svg +2 -2
- package/tests/examples/__snapshots__/example30.snap.svg +2 -2
- package/tests/examples/__snapshots__/example31.snap.svg +2 -2
- package/tests/examples/__snapshots__/example32.snap.svg +2 -2
- package/tests/examples/__snapshots__/example33.snap.svg +2 -2
- package/tests/examples/__snapshots__/example34.snap.svg +2 -2
- package/tests/examples/__snapshots__/example35.snap.svg +2 -2
- package/tests/examples/__snapshots__/example36.snap.svg +2 -2
- package/tests/examples/__snapshots__/example37.snap.svg +2 -2
- package/tests/examples/__snapshots__/example38.snap.svg +2 -2
- package/tests/examples/__snapshots__/example39.snap.svg +2 -2
- package/tests/examples/__snapshots__/example40.snap.svg +2 -2
- package/tests/examples/__snapshots__/example41.snap.svg +2 -2
- package/tests/examples/__snapshots__/example42.snap.svg +2 -2
- package/tests/examples/__snapshots__/example43.snap.svg +2 -2
- package/tests/examples/__snapshots__/example44.snap.svg +2 -2
- package/tests/examples/__snapshots__/example45.snap.svg +2 -2
- package/tests/examples/__snapshots__/example46.snap.svg +2 -2
- package/tests/examples/__snapshots__/example47.snap.svg +2 -2
- package/tests/examples/__snapshots__/example48.snap.svg +2 -2
- package/tests/examples/__snapshots__/example49.snap.svg +2 -2
- package/tests/examples/__snapshots__/example50.snap.svg +2 -2
- package/tests/examples/__snapshots__/example51.snap.svg +4 -4
- package/tests/fixtures/matcher.ts +3 -3
- package/tests/fixtures/parallel-ground-rail.ts +53 -0
- package/tests/repros/__snapshots__/board-1273-trace-overlap-cycle.snap.svg +4 -4
- package/tests/repros/__snapshots__/board-15984-same-net-junction.snap.svg +12 -12
- package/tests/repros/__snapshots__/board1096-usb-label-overlap-iteration.snap.svg +5 -5
- package/tests/repros/__snapshots__/bugreport-001-gnd-overlap.snap.svg +2 -2
- package/tests/repros/__snapshots__/manufacturePartNumber-text-box.snap.svg +2 -2
- package/tests/repros/__snapshots__/netlabel-connector-through-rail-label.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-atmega328p-fault-pullup.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-atmega328p-missing-gnd-netlabel.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-board-589-regulator-section.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-board-648-esp12f-section.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-bq24074-battery-charger.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-bq25895-cross-net-trace-overlap.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-cc2340r5.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-core-555-power-cross-net-overlap.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-core-subcircuit-missing-ground.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-core-tb67s579ftg-inline-label-routing.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-dc-power-isolated-routing.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-example35-minimize-trace-crossing.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-ground-label-on-lower-rail-end.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-ina237-current-monitor.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-missing-trace-netlabel.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-mspm0l1306-capacitor-symmetry.snap.svg +200 -0
- package/tests/repros/__snapshots__/repro-netlabel-collision-687.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-netlabel-overlap-trace.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-nrf52810-clock-routing.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-pga300-c6-trace-alignment.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-pga300-redundant-ground-traces.snap.svg +288 -0
- package/tests/repros/__snapshots__/repro-pmp11282-isolated-dcdc.snap.svg +4 -4
- package/tests/repros/__snapshots__/repro-power-group-rail-labels.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-rectifier-trace-overlap.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-rp2040-gamepad-trace-alignment.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-rp2040-usb-cc2-ground-overlap.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-rp2040-v3v3-label-placement.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-rp2040-zero-crystal-fallback-netlabels.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-ti-power-output-section.snap.svg +4 -4
- package/tests/repros/__snapshots__/repro-tida00553-j4-cell-divider.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-tida010076-j4-ground-bus.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-tida010076-page02.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-tps61222-trace-intersection.snap.svg +4 -4
- package/tests/repros/__snapshots__/repro-type-c-16pin-self-connection.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-type-c-16pin-to-resistor.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-type-c-vbus-led-ground-label.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-usb-power-vbus-label-detour.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-vcc-pin1-detour.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro129-host-custom-symbol-passives.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro130-bq27441-fuel-gauge-trace-through-c1.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro161-power-section-autolayout.snap.svg +4 -4
- package/tests/repros/__snapshots__/repro47-endpoint-obstacle-detour.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro48-555-timer-vcc-rail-label.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro5-escape-padded-text-obstacles.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro51-overlap-junction-crossing.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro84-stacked-gnd-label-orientation.snap.svg +2 -2
- package/tests/repros/__snapshots__/small-variant-resistor-facing-direction.snap.svg +2 -2
- package/tests/repros/__snapshots__/trace-overlap-box-resistor.snap.svg +2 -2
- package/tests/repros/assets/repro-mspm0l1306-capacitor-symmetry.input.json +537 -0
- package/tests/repros/assets/repro-pga300-redundant-ground-traces.input.json +858 -0
- package/tests/repros/repro-mspm0l1306-capacitor-symmetry.test.ts +87 -0
- package/tests/repros/repro-pga300-redundant-ground-traces.test.ts +33 -0
- package/tests/solvers/InlineNetLabelSolver/__snapshots__/anchored-net-label-width.snap.svg +2 -2
- package/tests/solvers/InlineNetLabelSolver/__snapshots__/inline-net-label-anchored-label-clearance.snap.svg +2 -2
- package/tests/solvers/InlineNetLabelSolver/__snapshots__/inline-net-label-port-stub.snap.svg +2 -2
- package/tests/solvers/InlineNetLabelSolver/__snapshots__/inline-net-label-two-pin-net.snap.svg +2 -2
- package/tests/solvers/InlineNetLabelSolver/__snapshots__/inline-net-label01.snap.svg +2 -2
- package/tests/solvers/InlineNetLabelSolver/__snapshots__/inline-net-label02.snap.svg +2 -2
- package/tests/solvers/InlineNetLabelSolver/__snapshots__/terminal-stub-trace-clearance.snap.svg +2 -2
- package/tests/solvers/MspConnectionPairSolver/local-ground-branches.test.ts +105 -0
- package/tests/solvers/SameNetJunctionAlignmentSolver/ground-rail-label.test.ts +188 -0
- package/tests/solvers/SameNetJunctionAlignmentSolver/parallel-load-rails.test.ts +291 -0
- package/tests/solvers/SchematicTraceSingleLineSolver2/__snapshots__/SchematicTraceSingleLineSolver2_01-example17-d1_1-u1_1.snap.svg +2 -2
- package/tests/solvers/SchematicTraceSingleLineSolver2/__snapshots__/SchematicTraceSingleLineSolver2_repro47-short-opposing-pins.snap.svg +2 -2
- package/tests/solvers/TraceCleanupSolver/__snapshots__/TraceCleanupSolver.snap.svg +2 -2
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/__snapshots__/TraceLabelOverlapAvoidanceSolver.snap.svg +2 -2
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/MergedNetLabelObstacles.snap.svg +2 -2
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/OverlapAvoidanceStepSolver.snap.svg +2 -2
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/SingleOverlapSolver.snap.svg +2 -2
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
|
|
3
|
+
import type { InputProblem } from "lib/types/InputProblem"
|
|
4
|
+
import "tests/fixtures/matcher"
|
|
5
|
+
import inputProblem from "./assets/repro-mspm0l1306-capacitor-symmetry.input.json"
|
|
6
|
+
|
|
7
|
+
// Captured from tscircuit/ti#119, Microcontroller_MSPM0L1306 at b5ee159.
|
|
8
|
+
// Only opaque component/port IDs and display metadata were normalized.
|
|
9
|
+
// C1/C2 are already level; their VDD/VSS rail junctions should be level too.
|
|
10
|
+
test("repro: MSPM0L1306 aligned decoupling capacitor rails", async () => {
|
|
11
|
+
const solver = new SchematicTracePipelineSolver(
|
|
12
|
+
inputProblem as unknown as InputProblem,
|
|
13
|
+
{
|
|
14
|
+
hideRatsNet: true,
|
|
15
|
+
},
|
|
16
|
+
)
|
|
17
|
+
solver.solve()
|
|
18
|
+
|
|
19
|
+
expect(solver.solved).toBe(true)
|
|
20
|
+
expect(solver.failed).toBe(false)
|
|
21
|
+
|
|
22
|
+
const { traces, netLabelPlacements } =
|
|
23
|
+
solver.netLabelToTraceSolver!.getOutput()
|
|
24
|
+
const getTrace = (...pinIds: string[]) => {
|
|
25
|
+
const trace = traces.find((trace) =>
|
|
26
|
+
pinIds.every((pinId) => trace.pinIds.includes(pinId)),
|
|
27
|
+
)
|
|
28
|
+
expect(trace).toBeDefined()
|
|
29
|
+
return trace!
|
|
30
|
+
}
|
|
31
|
+
for (const [pin, railY] of [
|
|
32
|
+
[1, 2.05],
|
|
33
|
+
[2, 0.65],
|
|
34
|
+
] as const) {
|
|
35
|
+
const path = getTrace(`C1.${pin}`, `C2.${pin}`).tracePath
|
|
36
|
+
const horizontalSegments = path.slice(1).flatMap((end, index) => {
|
|
37
|
+
const start = path[index]!
|
|
38
|
+
return Math.abs(start.y - end.y) < 1e-6 ? [[start, end]] : []
|
|
39
|
+
})
|
|
40
|
+
expect(horizontalSegments).toHaveLength(1)
|
|
41
|
+
const [start, end] = horizontalSegments[0]!
|
|
42
|
+
expect(start!.y).toBeCloseTo(railY, 6)
|
|
43
|
+
expect(end!.y).toBeCloseTo(railY, 6)
|
|
44
|
+
expect([start!.x, end!.x].sort()).toEqual([-3.5, -4.5].sort())
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// C3 and C4 share the electrical GND net with the decoupling rail, but
|
|
48
|
+
// should each terminate locally instead of being wired to other capacitors.
|
|
49
|
+
for (const pinId of ["C3.2", "C4.2"]) {
|
|
50
|
+
expect(
|
|
51
|
+
traces.some(
|
|
52
|
+
(trace) => trace.pinIds.includes(pinId) && trace.pinIds.length > 1,
|
|
53
|
+
),
|
|
54
|
+
).toBe(false)
|
|
55
|
+
expect(
|
|
56
|
+
netLabelPlacements.some(
|
|
57
|
+
(label) =>
|
|
58
|
+
label.netId === "GND" &&
|
|
59
|
+
label.pinIds.includes(pinId) &&
|
|
60
|
+
label.orientation === "y-",
|
|
61
|
+
),
|
|
62
|
+
).toBe(true)
|
|
63
|
+
}
|
|
64
|
+
const railGround = netLabelPlacements.find(
|
|
65
|
+
(label) =>
|
|
66
|
+
label.netId === "GND" &&
|
|
67
|
+
label.mspConnectionPairIds.some((pairId) =>
|
|
68
|
+
traces.some(
|
|
69
|
+
(trace) =>
|
|
70
|
+
trace.mspPairId === pairId && trace.pinIds.includes("C1.2"),
|
|
71
|
+
),
|
|
72
|
+
),
|
|
73
|
+
)
|
|
74
|
+
expect(railGround).toBeDefined()
|
|
75
|
+
expect(railGround!.orientation).toBe("y-")
|
|
76
|
+
expect(railGround!.anchorPoint.x).toBeCloseTo(-4.5, 6)
|
|
77
|
+
expect(railGround!.anchorPoint.y).toBeCloseTo(0.65, 6)
|
|
78
|
+
const groundNetId =
|
|
79
|
+
solver.mspConnectionPairSolver!.globalConnMap.getNetConnectedToId("GND")
|
|
80
|
+
expect(
|
|
81
|
+
netLabelPlacements
|
|
82
|
+
.filter((label) => label.netId === "GND")
|
|
83
|
+
.every((label) => label.globalConnNetId === groundNetId),
|
|
84
|
+
).toBe(true)
|
|
85
|
+
|
|
86
|
+
await expect(solver).toMatchSolverSnapshot(import.meta.path)
|
|
87
|
+
})
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
|
|
3
|
+
import type { InputProblem } from "lib/types/InputProblem"
|
|
4
|
+
import "tests/fixtures/matcher"
|
|
5
|
+
import inputProblem from "./assets/repro-pga300-redundant-ground-traces.input.json"
|
|
6
|
+
|
|
7
|
+
// Full solver input captured from tscircuit/ti#117 at 067b6a2 using
|
|
8
|
+
// `tsci build ... --schematic-only --disable-pcb --solver-debug`.
|
|
9
|
+
// Only the debug serializer's { value_type: "undefined" } markers were removed.
|
|
10
|
+
const COMP = "schematic_port_10"
|
|
11
|
+
const GND = "schematic_port_7"
|
|
12
|
+
const C3_GND = "schematic_port_32"
|
|
13
|
+
const R1_GND = "schematic_port_38"
|
|
14
|
+
|
|
15
|
+
test("repro: PGA300 adds redundant ground branches at COMP", async () => {
|
|
16
|
+
const solver = new SchematicTracePipelineSolver(
|
|
17
|
+
inputProblem as unknown as InputProblem,
|
|
18
|
+
)
|
|
19
|
+
solver.solve()
|
|
20
|
+
|
|
21
|
+
expect(solver.solved).toBe(true)
|
|
22
|
+
const { traces } = solver.netLabelToTraceSolver!.getOutput()
|
|
23
|
+
const hasPair = (a: string, b: string) =>
|
|
24
|
+
traces.some((trace) => trace.pinIds.includes(a) && trace.pinIds.includes(b))
|
|
25
|
+
|
|
26
|
+
// Current bug: the global GND spanning tree substitutes these two branches
|
|
27
|
+
// for the explicitly requested COMP -> R1 connection in the source circuit.
|
|
28
|
+
expect(hasPair(COMP, GND)).toBe(true)
|
|
29
|
+
expect(hasPair(COMP, C3_GND)).toBe(true)
|
|
30
|
+
expect(hasPair(COMP, R1_GND)).toBe(false)
|
|
31
|
+
|
|
32
|
+
await expect(solver).toMatchSolverSnapshot(import.meta.path)
|
|
33
|
+
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<svg width="
|
|
1
|
+
<svg width="1200" height="2016" viewBox="0 0 1200 2016" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Solver debug visualization on top and Circuit JSON schematic on the bottom">
|
|
2
2
|
<g transform="translate(0, 0) scale(1.875, 1.875) translate(0, 0)">
|
|
3
3
|
<rect width="100%" height="100%" fill="white"/><g><polyline data-points="5.575,1.4 2.045,2.6" data-type="line" data-label="" points="447.56446991404016,256.8863419293219 258.75835721107927,192.70296084049664" fill="none" stroke="hsl(193, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="5.575,1.2 2.045,2.4" data-type="line" data-label="" points="447.56446991404016,267.5835721107927 258.75835721107927,203.40019102196752" fill="none" stroke="hsl(191, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="5.575,1 2.045,2.2" data-type="line" data-label="" points="447.56446991404016,278.2808022922636 258.75835721107927,214.0974212034384" fill="none" stroke="hsl(72, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="5.575,0.8 2.045,2" data-type="line" data-label="" points="447.56446991404016,288.97803247373446 258.75835721107927,224.79465138490926" fill="none" stroke="hsl(74, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="5.575,0.6 2.045,0.7" data-type="line" data-label="" points="447.56446991404016,299.67526265520536 258.75835721107927,294.3266475644699" fill="none" stroke="hsl(184, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="5.575,1.4 5.375,1.4 5.375,2.6 2.045,2.6" data-type="line" data-label="" points="447.56446991404016,256.8863419293219 436.86723973256926,256.8863419293219 436.86723973256926,192.70296084049664 258.75835721107927,192.70296084049664" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="5.575,1.2 3.81,1.2 3.81,2.4 2.045,2.4" data-type="line" data-label="" points="447.56446991404016,267.5835721107927 353.1614135625597,267.5835721107927 353.1614135625597,203.40019102196752 258.75835721107927,203.40019102196752" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="5.575,1 3.71,1 3.71,2.2 2.045,2.2" data-type="line" data-label="" points="447.56446991404016,278.2808022922636 347.81279847182424,278.2808022922636 347.81279847182424,214.0974212034384 258.75835721107927,214.0974212034384" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="5.575,0.8 2.245,0.8 2.245,2 2.045,2" data-type="line" data-label="" points="447.56446991404016,288.97803247373446 269.4555873925501,288.97803247373446 269.4555873925501,224.79465138490926 258.75835721107927,224.79465138490926" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="5.575,0.6 3.81,0.6 3.81,0.7 2.045,0.7" data-type="line" data-label="" points="447.56446991404016,299.67526265520536 353.1614135625597,299.67526265520536 353.1614135625597,294.3266475644699 258.75835721107927,294.3266475644699" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="U1" data-x="0" data-y="0" x="40" y="161.9484240687679" width="218.75835721107927" height="339.6370582617001" fill="hsl(164, 100%, 50%, 0.8)" stroke="black" stroke-width="0.018696428571428572"/></g><g><rect data-type="rect" data-label="J4" data-x="7" data-y="-0.4" x="447.5644699140401" y="246.189111747851" width="152.43553008595984" height="213.94460362941737" fill="hsl(186, 100%, 50%, 0.8)" stroke="black" stroke-width="0.018696428571428572"/></g><g><rect data-type="rect" data-label="TB67S579FTG" data-x="2.405" data-y="3.525" x="242.71251193887292" y="138.41451766953202" width="70.60171919770775" height="9.627507163323742" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.018696428571428572"/></g><g><rect data-type="rect" data-label="U1" data-x="1.865" data-y="3.29" x="239.50334288443167" y="149.11174785100286" width="19.25501432664757" height="13.371537726838596" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.018696428571428572"/></g><g><rect data-type="rect" data-label="J4" data-x="6.095" data-y="1.715" x="465.74976122254054" y="233.35243553008593" width="19.255014326647597" height="13.371537726838568" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.018696428571428572"/></g><g><rect data-type="rect" data-label="INLINE netId: OUT_A_P
|
|
4
4
|
axis: x
|
|
@@ -70,7 +70,7 @@ SERIAL_IN" data-x="4.6925" data-y="0.6" cx="400.3629417382999" cy="299.675262655
|
|
|
70
70
|
});
|
|
71
71
|
]]></script>
|
|
72
72
|
</g>
|
|
73
|
-
<g transform="translate(
|
|
73
|
+
<g transform="translate(0, 1216)">
|
|
74
74
|
<style>
|
|
75
75
|
.boundary { fill: rgb(245, 241, 237); }
|
|
76
76
|
.schematic-boundary { fill: none; stroke: #fff; }
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<svg width="
|
|
1
|
+
<svg width="1200" height="2016" viewBox="0 0 1200 2016" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Solver debug visualization on top and Circuit JSON schematic on the bottom">
|
|
2
2
|
<g transform="translate(0, 0) scale(1.875, 1.875) translate(0, 0)">
|
|
3
3
|
<rect width="100%" height="100%" fill="white"/><g><polyline data-points="-0.7,0.2 -1.3290000000000002,0.2" data-type="line" data-label="" points="337.7926421404682,320 219.98662207357856,320" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-0.7,0.4 -1.3290000000000002,0.4" data-type="line" data-label="" points="337.7926421404682,282.54180602006693 219.98662207357856,282.54180602006693" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-0.7,0 -1.38,0" data-type="line" data-label="" points="337.7926421404682,357.4581939799331 210.43478260869568,357.4581939799331" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="U1" data-x="0" data-y="0.2" x="337.79264214046816" y="226.35451505016724" width="262.2073578595318" height="187.29096989966553" fill="hsl(164, 100%, 50%, 0.8)" stroke="black" stroke-width="0.005339285714285715"/></g><g><rect data-type="rect" data-label="netId: D_MINUS
|
|
4
4
|
globalConnNetId: connectivity_net0" data-x="-1.81" data-y="0.4" x="40" y="263.81270903010034" width="179.79933110367892" height="37.45819397993313" fill="hsl(40, 100%, 50%, 0.35)" stroke="black" stroke-width="0.005339285714285715"/></g><g><rect data-type="rect" data-label="netId: D_PLUS
|
|
@@ -55,7 +55,7 @@ SWCLK" data-x="-1.04" data-y="0" cx="274.11371237458195" cy="357.4581939799331"
|
|
|
55
55
|
});
|
|
56
56
|
]]></script>
|
|
57
57
|
</g>
|
|
58
|
-
<g transform="translate(
|
|
58
|
+
<g transform="translate(0, 1216)">
|
|
59
59
|
<style>
|
|
60
60
|
.boundary { fill: rgb(245, 241, 237); }
|
|
61
61
|
.schematic-boundary { fill: none; stroke: #fff; }
|
package/tests/solvers/InlineNetLabelSolver/__snapshots__/inline-net-label-port-stub.snap.svg
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<svg width="
|
|
1
|
+
<svg width="1200" height="2016" viewBox="0 0 1200 2016" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Solver debug visualization on top and Circuit JSON schematic on the bottom">
|
|
2
2
|
<g transform="translate(0, 0) scale(1.875, 1.875) translate(0, 0)">
|
|
3
3
|
<rect width="100%" height="100%" fill="white"/><g><polyline data-points="-0.5,0.3 -2.3499999999999996,0.3" data-type="line" data-label="" points="262.79569892473114,271.8279569892473 40,271.8279569892473" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="0.5,-0.2 2.3,-0.2" data-type="line" data-label="" points="383.2258064516129,332.04301075268813 600,332.04301075268813" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-0.5,-0.1 -2.3499999999999996,-0.1" data-type="line" data-label="" points="262.79569892473114,320 40,320" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-0.2,0.5 -0.2,1.45" data-type="line" data-label="" points="298.9247311827957,247.74193548387095 298.9247311827957,133.33333333333331" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="0.2,-0.5 0.2,-1.65" data-type="line" data-label="" points="347.09677419354836,368.17204301075265 347.09677419354836,506.66666666666663" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="U1" data-x="0" data-y="0" x="262.79569892473114" y="247.74193548387098" width="120.43010752688178" height="120.4301075268817" fill="hsl(164, 100%, 50%, 0.8)" stroke="black" stroke-width="0.008303571428571428"/></g><g><rect data-type="rect" data-label="INLINE netId: NET_PRU0_MII_TX_CLK1
|
|
4
4
|
axis: x
|
|
@@ -65,7 +65,7 @@ NET_BOTTOM" data-x="0.2" data-y="-1.075" cx="347.09677419354836" cy="437.4193548
|
|
|
65
65
|
});
|
|
66
66
|
]]></script>
|
|
67
67
|
</g>
|
|
68
|
-
<g transform="translate(
|
|
68
|
+
<g transform="translate(0, 1216)">
|
|
69
69
|
<style>
|
|
70
70
|
.boundary { fill: rgb(245, 241, 237); }
|
|
71
71
|
.schematic-boundary { fill: none; stroke: #fff; }
|
package/tests/solvers/InlineNetLabelSolver/__snapshots__/inline-net-label-two-pin-net.snap.svg
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<svg width="
|
|
1
|
+
<svg width="1200" height="2016" viewBox="0 0 1200 2016" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Solver debug visualization on top and Circuit JSON schematic on the bottom">
|
|
2
2
|
<g transform="translate(0, 0) scale(1.875, 1.875) translate(0, 0)">
|
|
3
3
|
<rect width="100%" height="100%" fill="white"/><g><polyline data-points="-0.5,1 0.5,1" data-type="line" data-label="" points="264,208 376,208" fill="none" stroke="hsl(253, 100%, 50%, 0.8)" stroke-width="1px" stroke-dasharray="4 2"/></g><g><polyline data-points="-0.5,1 0.5,1" data-type="line" data-label="" points="264,208 376,208" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="-1.5,-1 -0.19999999999999996,-1" data-type="line" data-label="" points="152,432 297.6,432" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="1.5,-1 0.19999999999999996,-1" data-type="line" data-label="" points="488,432 342.4,432" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="U1" data-x="-1" data-y="1" x="152" y="152" width="112" height="112" fill="hsl(164, 100%, 50%, 0.8)" stroke="black" stroke-width="0.008928571428571428"/></g><g><rect data-type="rect" data-label="U2" data-x="1" data-y="1" x="376" y="152" width="112" height="112" fill="hsl(165, 100%, 50%, 0.8)" stroke="black" stroke-width="0.008928571428571428"/></g><g><rect data-type="rect" data-label="U3" data-x="-2" data-y="-1" x="40" y="376" width="112" height="112" fill="hsl(166, 100%, 50%, 0.8)" stroke="black" stroke-width="0.008928571428571428"/></g><g><rect data-type="rect" data-label="U4" data-x="2" data-y="-1" x="488" y="376" width="112" height="112" fill="hsl(167, 100%, 50%, 0.8)" stroke="black" stroke-width="0.008928571428571428"/></g><g><rect data-type="rect" data-label="INLINE netId: NET_ROUTED
|
|
4
4
|
axis: x
|
|
@@ -58,7 +58,7 @@ NET_SECTIONED" data-x="0.85" data-y="-1" cx="415.2" cy="432" r="3" fill="green"/
|
|
|
58
58
|
});
|
|
59
59
|
]]></script>
|
|
60
60
|
</g>
|
|
61
|
-
<g transform="translate(
|
|
61
|
+
<g transform="translate(0, 1216)">
|
|
62
62
|
<style>
|
|
63
63
|
.boundary { fill: rgb(245, 241, 237); }
|
|
64
64
|
.schematic-boundary { fill: none; stroke: #fff; }
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<svg width="
|
|
1
|
+
<svg width="1200" height="2016" viewBox="0 0 1200 2016" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Solver debug visualization on top and Circuit JSON schematic on the bottom">
|
|
2
2
|
<g transform="translate(0, 0) scale(1.875, 1.875) translate(0, 0)">
|
|
3
3
|
<rect width="100%" height="100%" fill="white"/><g><polyline data-points="0.5,0 2.5,0" data-type="line" data-label="" points="214.33962264150944,71.69811320754715 425.66037735849056,71.69811320754715" fill="none" stroke="hsl(48, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0,-2.5 0,-4" data-type="line" data-label="" points="161.50943396226415,335.84905660377353 161.50943396226415,494.33962264150944" fill="none" stroke="hsl(136, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0.5,0 2.5,0" data-type="line" data-label="" points="214.33962264150944,71.69811320754715 425.66037735849056,71.69811320754715" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="0,-2.5 0,-4" data-type="line" data-label="" points="161.50943396226415,335.84905660377353 161.50943396226415,494.33962264150944" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="U1" data-x="0" data-y="0" x="108.67924528301887" y="39.999999999999986" width="105.66037735849056" height="63.39622641509433" fill="hsl(164, 100%, 50%, 0.8)" stroke="black" stroke-width="0.009464285714285715"/></g><g><rect data-type="rect" data-label="U2" data-x="3" data-y="0" x="425.66037735849056" y="39.999999999999986" width="105.66037735849056" height="63.39622641509433" fill="hsl(165, 100%, 50%, 0.8)" stroke="black" stroke-width="0.009464285714285715"/></g><g><rect data-type="rect" data-label="U3" data-x="0" data-y="-2" x="129.81132075471697" y="230.18867924528303" width="63.39622641509436" height="105.66037735849054" fill="hsl(166, 100%, 50%, 0.8)" stroke="black" stroke-width="0.009464285714285715"/></g><g><rect data-type="rect" data-label="U4" data-x="0" data-y="-4.5" x="129.81132075471697" y="494.3396226415094" width="63.39622641509436" height="105.66037735849056" fill="hsl(167, 100%, 50%, 0.8)" stroke="black" stroke-width="0.009464285714285715"/></g><g><rect data-type="rect" data-label="INLINE netId: USER_LED_ANODE
|
|
4
4
|
axis: x
|
|
@@ -55,7 +55,7 @@ SPI_SCK" data-x="0" data-y="-3.25" cx="161.50943396226415" cy="415.0943396226415
|
|
|
55
55
|
});
|
|
56
56
|
]]></script>
|
|
57
57
|
</g>
|
|
58
|
-
<g transform="translate(
|
|
58
|
+
<g transform="translate(0, 1216)">
|
|
59
59
|
<style>
|
|
60
60
|
.boundary { fill: rgb(245, 241, 237); }
|
|
61
61
|
.schematic-boundary { fill: none; stroke: #fff; }
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<svg width="
|
|
1
|
+
<svg width="1200" height="2016" viewBox="0 0 1200 2016" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Solver debug visualization on top and Circuit JSON schematic on the bottom">
|
|
2
2
|
<g transform="translate(0, 0) scale(1.875, 1.875) translate(0, 0)">
|
|
3
3
|
<rect width="100%" height="100%" fill="white"/><g><polyline data-points="0.6000000000000001,-0.30000000000000004 2.435,0" data-type="line" data-label="" points="201.34453781512605,376.47058823529414 448.06722689075633,336.1344537815126" fill="none" stroke="hsl(48, 100%, 50%, 0.8)" stroke-width="1px"/></g><g><polyline data-points="0.6000000000000001,-0.30000000000000004 1.5175,-0.30000000000000004 1.5175,0 2.435,0" data-type="line" data-label="" points="201.34453781512605,376.47058823529414 324.7058823529412,376.47058823529414 324.7058823529412,336.1344537815126 448.06722689075633,336.1344537815126" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="schematic_component_0" data-x="0" data-y="0" x="40" y="268.9075630252101" width="161.34453781512605" height="134.45378151260502" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.0074375"/></g><g><rect data-type="rect" data-label="schematic_component_1" data-x="3" data-y="0.13249999999999998" x="448.0672268907564" y="256.8067226890756" width="151.93277310924367" height="123.02521008403363" fill="hsl(24, 100%, 50%, 0.8)" stroke="black" stroke-width="0.0074375"/></g><g><rect data-type="rect" data-label="U1" data-x="-0.08000000000000002" data-y="0.615" x="85.7142857142857" y="236.6386554621849" width="48.40336134453783" height="33.613445378151255" fill="rgba(160, 0, 220, 0.14)" stroke="black" stroke-width="0.0074375"/></g><g><rect data-type="rect" data-label="INLINE netId: USER_LED_ANODE
|
|
4
4
|
axis: x
|
|
@@ -58,7 +58,7 @@ USER_LED_ANODE" data-x="1.5175" data-y="0" cx="324.7058823529412" cy="336.134453
|
|
|
58
58
|
});
|
|
59
59
|
]]></script>
|
|
60
60
|
</g>
|
|
61
|
-
<g transform="translate(
|
|
61
|
+
<g transform="translate(0, 1216)">
|
|
62
62
|
<style>
|
|
63
63
|
.boundary { fill: rgb(245, 241, 237); }
|
|
64
64
|
.schematic-boundary { fill: none; stroke: #fff; }
|
package/tests/solvers/InlineNetLabelSolver/__snapshots__/terminal-stub-trace-clearance.snap.svg
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<svg width="
|
|
1
|
+
<svg width="1200" height="2016" viewBox="0 0 1200 2016" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Solver debug visualization on top and Circuit JSON schematic on the bottom">
|
|
2
2
|
<g transform="translate(0, 0) scale(1.875, 1.875) translate(0, 0)">
|
|
3
3
|
<rect width="100%" height="100%" fill="white"/><g><polyline data-points="0.5,-0.1 1,-0.1 1,0.5" data-type="line" data-label="" points="413.33333333333337,394.66666666666663 600,394.66666666666663 600,170.66666666666666" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="0.5,0.3 0.95,0.3" data-type="line" data-label="" points="413.33333333333337,245.33333333333331 581.3333333333333,245.33333333333331" fill="none" stroke="purple" stroke-width="1px"/></g><g><polyline data-points="0.5,0.1 0.95,0.1" data-type="line" data-label="" points="413.33333333333337,320 581.3333333333333,320" fill="none" stroke="purple" stroke-width="1px"/></g><g><rect data-type="rect" data-label="U1" data-x="0" data-y="0.1" x="40" y="170.66666666666669" width="373.33333333333337" height="298.66666666666663" fill="hsl(164, 100%, 50%, 0.8)" stroke="black" stroke-width="0.0026785714285714286"/></g><g><rect data-type="rect" data-label="INLINE netId: SCL
|
|
4
4
|
axis: x
|
|
@@ -54,7 +54,7 @@ SDA" data-x="0.725" data-y="0.1" cx="497.3333333333333" cy="320" r="3" fill="gre
|
|
|
54
54
|
});
|
|
55
55
|
]]></script>
|
|
56
56
|
</g>
|
|
57
|
-
<g transform="translate(
|
|
57
|
+
<g transform="translate(0, 1216)">
|
|
58
58
|
<style>
|
|
59
59
|
.boundary { fill: rgb(245, 241, 237); }
|
|
60
60
|
.schematic-boundary { fill: none; stroke: #fff; }
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { LongDistancePairSolver } from "lib/solvers/LongDistancePairSolver/LongDistancePairSolver"
|
|
3
|
+
import { getGroundConnectionPolicy } from "lib/solvers/MspConnectionPairSolver/getGroundConnectionPolicy"
|
|
4
|
+
import { MspConnectionPairSolver } from "lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver"
|
|
5
|
+
import { createParallelGroundRailProblem } from "tests/fixtures/parallel-ground-rail"
|
|
6
|
+
|
|
7
|
+
test("keeps a wired parallel ground rail but labels independent staggered branches", () => {
|
|
8
|
+
const inputProblem = createParallelGroundRailProblem()
|
|
9
|
+
const before = structuredClone(inputProblem)
|
|
10
|
+
const solver = new MspConnectionPairSolver({ inputProblem })
|
|
11
|
+
solver.solve()
|
|
12
|
+
expect(solver.mspConnectionPairs).toHaveLength(2)
|
|
13
|
+
const routed = new Set(
|
|
14
|
+
solver.mspConnectionPairs.flatMap((pair) =>
|
|
15
|
+
pair.pins.map((pin) => pin.pinId),
|
|
16
|
+
),
|
|
17
|
+
)
|
|
18
|
+
expect([...routed].sort()).toEqual(["A.2", "B.2", "U.GND"])
|
|
19
|
+
expect(inputProblem).toEqual(before)
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
test("long-distance recovery does not reconnect the separated ground branches", () => {
|
|
23
|
+
const inputProblem = createParallelGroundRailProblem()
|
|
24
|
+
const primary = new MspConnectionPairSolver({ inputProblem })
|
|
25
|
+
primary.solve()
|
|
26
|
+
const solver = new LongDistancePairSolver({
|
|
27
|
+
inputProblem,
|
|
28
|
+
primaryMspConnectionPairs: primary.mspConnectionPairs,
|
|
29
|
+
alreadySolvedTraces: [],
|
|
30
|
+
failedConnectionPairs: [],
|
|
31
|
+
})
|
|
32
|
+
solver.solve()
|
|
33
|
+
expect(solver.getOutput().newTraces).toEqual([])
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test("the branch policy is symmetric in its endpoints", () => {
|
|
37
|
+
const canRoute = getGroundConnectionPolicy(createParallelGroundRailProblem())
|
|
38
|
+
expect(canRoute("B.2", "C.2")).toBe(false)
|
|
39
|
+
expect(canRoute("C.2", "B.2")).toBe(false)
|
|
40
|
+
expect(canRoute("C.2", "D.2")).toBe(false)
|
|
41
|
+
expect(canRoute("D.2", "C.2")).toBe(false)
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test("explicit direct wiring overrides the local-ground preference", () => {
|
|
45
|
+
const inputProblem = createParallelGroundRailProblem()
|
|
46
|
+
inputProblem.directConnections.push({ pinIds: ["B.2", "C.2"] })
|
|
47
|
+
const canRoute = getGroundConnectionPolicy(inputProblem)
|
|
48
|
+
expect(canRoute("B.2", "C.2")).toBe(true)
|
|
49
|
+
expect(canRoute("A.2", "C.2")).toBe(true)
|
|
50
|
+
expect(canRoute("C.2", "D.2")).toBe(false)
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
for (const y of [1, 0.5, 0]) {
|
|
54
|
+
test(`keeps level or nearby ground pins at y=${y} on the rail`, () => {
|
|
55
|
+
const inputProblem = createParallelGroundRailProblem()
|
|
56
|
+
inputProblem.chips[2]!.pins[1]!.y = y
|
|
57
|
+
const canRoute = getGroundConnectionPolicy(inputProblem)
|
|
58
|
+
expect(canRoute("B.2", "C.2")).toBe(true)
|
|
59
|
+
})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
test("preserves existing behavior without an explicitly wired parallel rail", () => {
|
|
63
|
+
const inputProblem = createParallelGroundRailProblem()
|
|
64
|
+
inputProblem.directConnections = []
|
|
65
|
+
expect(getGroundConnectionPolicy(inputProblem)("B.2", "C.2")).toBe(true)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test("a repeated direct-connection net ID does not invent a physical rail", () => {
|
|
69
|
+
const inputProblem = createParallelGroundRailProblem()
|
|
70
|
+
inputProblem.directConnections = [
|
|
71
|
+
{ netId: "GND", pinIds: ["A.2", "U.GND"] },
|
|
72
|
+
{ netId: "GND", pinIds: ["B.2", "D.2"] },
|
|
73
|
+
]
|
|
74
|
+
expect(getGroundConnectionPolicy(inputProblem)("B.2", "C.2")).toBe(true)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
test("resolves a ground alias through global connectivity", () => {
|
|
78
|
+
const inputProblem = createParallelGroundRailProblem()
|
|
79
|
+
inputProblem.netConnections[0]!.netId = "RETURN"
|
|
80
|
+
inputProblem.netConnections.push({ netId: "GND", pinIds: ["U.GND"] })
|
|
81
|
+
expect(getGroundConnectionPolicy(inputProblem)("B.2", "C.2")).toBe(false)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
test("does not apply the ground rule to power or signal nets", () => {
|
|
85
|
+
const inputProblem = createParallelGroundRailProblem()
|
|
86
|
+
inputProblem.netConnections[0]!.netId = "VDD"
|
|
87
|
+
expect(getGroundConnectionPolicy(inputProblem)("B.2", "C.2")).toBe(true)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
test("infers ground-facing pins when explicit directions are absent", () => {
|
|
91
|
+
const inputProblem = createParallelGroundRailProblem()
|
|
92
|
+
for (const chip of inputProblem.chips) {
|
|
93
|
+
for (const pin of chip.pins) delete pin._facingDirection
|
|
94
|
+
}
|
|
95
|
+
expect(getGroundConnectionPolicy(inputProblem)("B.2", "C.2")).toBe(false)
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
test("does not isolate side-facing or multi-pin components", () => {
|
|
99
|
+
const inputProblem = createParallelGroundRailProblem()
|
|
100
|
+
inputProblem.chips[2]!.pins[1]!._facingDirection = "x-"
|
|
101
|
+
expect(getGroundConnectionPolicy(inputProblem)("B.2", "C.2")).toBe(true)
|
|
102
|
+
inputProblem.chips[2]!.pins[1]!._facingDirection = "y-"
|
|
103
|
+
inputProblem.chips[2]!.pins.push({ pinId: "C.3", x: 2, y: -1.6 })
|
|
104
|
+
expect(getGroundConnectionPolicy(inputProblem)("B.2", "C.2")).toBe(true)
|
|
105
|
+
})
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { getConnectivityMapsFromInputProblem } from "lib/solvers/MspConnectionPairSolver/getConnectivityMapFromInputProblem"
|
|
3
|
+
import type { NetLabelPlacement } from "lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver"
|
|
4
|
+
import { placeGroundRailLabelsAtOuterEnd } from "lib/solvers/SameNetJunctionAlignmentSolver/placeGroundRailLabelsAtOuterEnd"
|
|
5
|
+
import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
6
|
+
import { createParallelGroundRailProblem } from "tests/fixtures/parallel-ground-rail"
|
|
7
|
+
|
|
8
|
+
const createFixture = () => {
|
|
9
|
+
const inputProblem = createParallelGroundRailProblem()
|
|
10
|
+
const { netConnMap } = getConnectivityMapsFromInputProblem(inputProblem)
|
|
11
|
+
const globalConnNetId = netConnMap.getNetConnectedToId("GND")!
|
|
12
|
+
const pins = new Map(
|
|
13
|
+
inputProblem.chips.flatMap((chip) =>
|
|
14
|
+
chip.pins.map(
|
|
15
|
+
(pin) => [pin.pinId, { ...pin, chipId: chip.chipId }] as const,
|
|
16
|
+
),
|
|
17
|
+
),
|
|
18
|
+
)
|
|
19
|
+
const trace = (
|
|
20
|
+
mspPairId: string,
|
|
21
|
+
pinIds: [string, string],
|
|
22
|
+
path: number[][],
|
|
23
|
+
): SolvedTracePath => ({
|
|
24
|
+
mspPairId,
|
|
25
|
+
mspConnectionPairIds: [mspPairId],
|
|
26
|
+
globalConnNetId,
|
|
27
|
+
dcConnNetId: globalConnNetId,
|
|
28
|
+
userNetId: "GND",
|
|
29
|
+
pinIds,
|
|
30
|
+
pins: [pins.get(pinIds[0])!, pins.get(pinIds[1])!],
|
|
31
|
+
tracePath: path.map(([x, y]) => ({ x: x!, y: y! })),
|
|
32
|
+
})
|
|
33
|
+
const traces = [
|
|
34
|
+
trace(
|
|
35
|
+
"rail",
|
|
36
|
+
["B.2", "A.2"],
|
|
37
|
+
[
|
|
38
|
+
[1, 1],
|
|
39
|
+
[1, 0.6],
|
|
40
|
+
[0, 0.6],
|
|
41
|
+
[0, 1],
|
|
42
|
+
],
|
|
43
|
+
),
|
|
44
|
+
trace(
|
|
45
|
+
"feed",
|
|
46
|
+
["U.GND", "B.2"],
|
|
47
|
+
[
|
|
48
|
+
[2, 0.6],
|
|
49
|
+
[1, 0.6],
|
|
50
|
+
[1, 1],
|
|
51
|
+
],
|
|
52
|
+
),
|
|
53
|
+
]
|
|
54
|
+
const netLabelPlacements: NetLabelPlacement[] = [
|
|
55
|
+
{
|
|
56
|
+
globalConnNetId,
|
|
57
|
+
dcConnNetId: globalConnNetId,
|
|
58
|
+
netId: "GND",
|
|
59
|
+
mspConnectionPairIds: ["feed"],
|
|
60
|
+
pinIds: ["U.GND", "B.2"],
|
|
61
|
+
orientation: "y-",
|
|
62
|
+
anchorPoint: { x: 1, y: 0.6 },
|
|
63
|
+
center: { x: 1, y: 0.4 },
|
|
64
|
+
width: 0.4,
|
|
65
|
+
height: 0.4,
|
|
66
|
+
},
|
|
67
|
+
]
|
|
68
|
+
return { inputProblem, traces, netLabelPlacements }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
for (const mirror of [1, -1]) {
|
|
72
|
+
test(`places the shared GND at the outer column, mirrored=${mirror}`, () => {
|
|
73
|
+
const fixture = createFixture()
|
|
74
|
+
for (const chip of fixture.inputProblem.chips) {
|
|
75
|
+
chip.center.x *= mirror
|
|
76
|
+
for (const pin of chip.pins) pin.x *= mirror
|
|
77
|
+
}
|
|
78
|
+
for (const trace of fixture.traces) {
|
|
79
|
+
for (const point of trace.tracePath) point.x *= mirror
|
|
80
|
+
}
|
|
81
|
+
const visited = new Set()
|
|
82
|
+
for (const pin of fixture.traces.flatMap((trace) => trace.pins)) {
|
|
83
|
+
if (visited.has(pin)) continue
|
|
84
|
+
pin.x *= mirror
|
|
85
|
+
visited.add(pin)
|
|
86
|
+
}
|
|
87
|
+
fixture.netLabelPlacements[0]!.anchorPoint.x *= mirror
|
|
88
|
+
fixture.netLabelPlacements[0]!.center.x *= mirror
|
|
89
|
+
const before = structuredClone(fixture)
|
|
90
|
+
const labels = placeGroundRailLabelsAtOuterEnd(fixture)
|
|
91
|
+
expect(labels[0]!.anchorPoint.x).toBeCloseTo(0, 6)
|
|
92
|
+
expect(labels[0]!.anchorPoint.y).toBeCloseTo(0.6, 6)
|
|
93
|
+
expect(labels[0]!.mspConnectionPairIds).toEqual(["rail"])
|
|
94
|
+
expect(labels[0]!.globalConnNetId).toBe(
|
|
95
|
+
before.netLabelPlacements[0]!.globalConnNetId,
|
|
96
|
+
)
|
|
97
|
+
expect(fixture).toEqual(before)
|
|
98
|
+
expect(
|
|
99
|
+
placeGroundRailLabelsAtOuterEnd({
|
|
100
|
+
...fixture,
|
|
101
|
+
netLabelPlacements: labels,
|
|
102
|
+
}),
|
|
103
|
+
).toEqual(labels)
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
test("label placement is independent of trace and endpoint ordering", () => {
|
|
108
|
+
const fixture = createFixture()
|
|
109
|
+
fixture.traces.reverse()
|
|
110
|
+
for (const trace of fixture.traces) {
|
|
111
|
+
trace.tracePath.reverse()
|
|
112
|
+
trace.pins.reverse()
|
|
113
|
+
trace.pinIds.reverse()
|
|
114
|
+
}
|
|
115
|
+
expect(placeGroundRailLabelsAtOuterEnd(fixture)[0]!.anchorPoint).toEqual({
|
|
116
|
+
x: 0,
|
|
117
|
+
y: 0.6,
|
|
118
|
+
})
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
for (const obstacle of [
|
|
122
|
+
"chip",
|
|
123
|
+
"text",
|
|
124
|
+
"trace",
|
|
125
|
+
"same-net-trace",
|
|
126
|
+
"label",
|
|
127
|
+
"same-net-label",
|
|
128
|
+
] as const) {
|
|
129
|
+
test(`keeps the existing anchor when the outer label would hit a ${obstacle}`, () => {
|
|
130
|
+
const fixture = createFixture()
|
|
131
|
+
const rect = { center: { x: 0, y: 0.4 }, width: 0.2, height: 0.2 }
|
|
132
|
+
if (obstacle === "chip")
|
|
133
|
+
fixture.inputProblem.chips.push({ ...rect, chipId: "obstacle", pins: [] })
|
|
134
|
+
if (obstacle === "text")
|
|
135
|
+
fixture.inputProblem.textBoxes = [{ ...rect, text: "annotation" }]
|
|
136
|
+
if (obstacle === "trace" || obstacle === "same-net-trace")
|
|
137
|
+
fixture.traces.push({
|
|
138
|
+
...fixture.traces[0]!,
|
|
139
|
+
mspPairId: "obstacle",
|
|
140
|
+
globalConnNetId:
|
|
141
|
+
obstacle === "trace" ? "foreign" : fixture.traces[0]!.globalConnNetId,
|
|
142
|
+
tracePath: [
|
|
143
|
+
{ x: -0.4, y: 0.4 },
|
|
144
|
+
{ x: 0.4, y: 0.4 },
|
|
145
|
+
],
|
|
146
|
+
})
|
|
147
|
+
if (obstacle === "label" || obstacle === "same-net-label")
|
|
148
|
+
fixture.netLabelPlacements.push({
|
|
149
|
+
...fixture.netLabelPlacements[0]!,
|
|
150
|
+
...rect,
|
|
151
|
+
globalConnNetId:
|
|
152
|
+
obstacle === "label"
|
|
153
|
+
? "foreign"
|
|
154
|
+
: fixture.netLabelPlacements[0]!.globalConnNetId,
|
|
155
|
+
mspConnectionPairIds: [],
|
|
156
|
+
pinIds: [],
|
|
157
|
+
anchorPoint: { x: 0, y: 0.5 },
|
|
158
|
+
})
|
|
159
|
+
expect(placeGroundRailLabelsAtOuterEnd(fixture)).toEqual(
|
|
160
|
+
fixture.netLabelPlacements,
|
|
161
|
+
)
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
test("does not move a port-only or unrelated island's GND label", () => {
|
|
166
|
+
const fixture = createFixture()
|
|
167
|
+
fixture.netLabelPlacements[0]!.mspConnectionPairIds = []
|
|
168
|
+
expect(placeGroundRailLabelsAtOuterEnd(fixture)).toEqual(
|
|
169
|
+
fixture.netLabelPlacements,
|
|
170
|
+
)
|
|
171
|
+
fixture.netLabelPlacements[0]!.mspConnectionPairIds = ["another-island"]
|
|
172
|
+
expect(placeGroundRailLabelsAtOuterEnd(fixture)).toEqual(
|
|
173
|
+
fixture.netLabelPlacements,
|
|
174
|
+
)
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
test("does not force staggered ground pins or power labels to an outer column", () => {
|
|
178
|
+
const fixture = createFixture()
|
|
179
|
+
fixture.traces[0]!.pins[0].y += 0.2
|
|
180
|
+
expect(placeGroundRailLabelsAtOuterEnd(fixture)).toEqual(
|
|
181
|
+
fixture.netLabelPlacements,
|
|
182
|
+
)
|
|
183
|
+
fixture.traces[0]!.pins[0].y -= 0.2
|
|
184
|
+
fixture.netLabelPlacements[0]!.orientation = "y+"
|
|
185
|
+
expect(placeGroundRailLabelsAtOuterEnd(fixture)).toEqual(
|
|
186
|
+
fixture.netLabelPlacements,
|
|
187
|
+
)
|
|
188
|
+
})
|