@tscircuit/schematic-trace-solver 0.0.118 → 0.0.120

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.
@@ -0,0 +1,95 @@
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
+
6
+ const inputProblem: InputProblem = {
7
+ chips: [
8
+ {
9
+ chipId: "U1",
10
+ center: { x: 0, y: 0 },
11
+ width: 2,
12
+ height: 1.4,
13
+ pins: [
14
+ ...[0.5, 0.25, 0, -0.25, -0.5].map((y, index) => ({
15
+ pinId: `U1.${index + 1}`,
16
+ x: -1,
17
+ y,
18
+ _facingDirection: "x-" as const,
19
+ })),
20
+ ...[0.5, 0.25, 0, -0.25, -0.5].map((y, index) => ({
21
+ pinId: `U1.${index + 6}`,
22
+ x: 1,
23
+ y,
24
+ _facingDirection: "x+" as const,
25
+ })),
26
+ ],
27
+ },
28
+ ],
29
+ directConnections: [],
30
+ netConnections: [
31
+ {
32
+ netId: "VBAT",
33
+ pinIds: ["U1.1", "U1.2", "U1.3"],
34
+ netLabelWidth: 0.48,
35
+ netLabelHeight: 0.48,
36
+ },
37
+ {
38
+ netId: "GND",
39
+ pinIds: ["U1.4", "U1.5"],
40
+ netLabelWidth: 0.36,
41
+ netLabelHeight: 0.48,
42
+ },
43
+ ],
44
+ textBoxes: [
45
+ {
46
+ chipId: "U1",
47
+ center: { x: -0.25, y: 0.85 },
48
+ width: 0.7,
49
+ height: 0.2,
50
+ text: "U1 Power",
51
+ },
52
+ ],
53
+ availableNetLabelOrientations: {
54
+ VBAT: ["y+"],
55
+ GND: ["y-"],
56
+ },
57
+ maxMspPairDistance: 2.4,
58
+ }
59
+
60
+ test("places same-side VBAT and GND labels at opposite rail ends", () => {
61
+ const solver = new SchematicTracePipelineSolver(inputProblem)
62
+
63
+ solver.solve()
64
+
65
+ const outputLabels =
66
+ solver.netLabelNetLabelCollisionSolver!.getOutput().netLabelPlacements
67
+ const u1 = solver.inputProblem.chips.find((chip) => chip.chipId === "U1")!
68
+ const chipLeft = u1.center.x - u1.width / 2
69
+
70
+ for (const expected of [
71
+ { netId: "VBAT", orientation: "y+" as const, anchorY: 0.5 },
72
+ { netId: "GND", orientation: "y-" as const, anchorY: -0.5 },
73
+ ]) {
74
+ const label = outputLabels.find(
75
+ (candidate) => candidate.netId === expected.netId,
76
+ )!
77
+ const connector = solver.availableNetOrientationSolver!.traces.find(
78
+ (trace) =>
79
+ trace.userNetId === expected.netId &&
80
+ trace.mspPairId.startsWith("available-net-orientation-"),
81
+ )!
82
+ const [connectorSource, connectorTarget] = connector.tracePath
83
+ const labelRight = label.center.x + label.width / 2
84
+
85
+ expect(label.orientation).toBe(expected.orientation)
86
+ expect(label.anchorPoint.y).toBeCloseTo(expected.anchorY)
87
+ expect(labelRight).toBeLessThan(chipLeft)
88
+ expect(connector.tracePath).toHaveLength(2)
89
+ expect(connectorSource!.y).toBeCloseTo(connectorTarget!.y)
90
+ expect(connectorTarget!.x).toBeLessThan(connectorSource!.x)
91
+ expect(connectorSource!.x - connectorTarget!.x).toBeLessThan(0.5)
92
+ }
93
+
94
+ expect(solver).toMatchSolverSnapshot(import.meta.path)
95
+ })
@@ -0,0 +1,102 @@
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
+
6
+ const createRp2040SidePins = (side: "left" | "right") =>
7
+ Array.from({ length: 22 }, (_, index) => ({
8
+ pinId: `U1.${side}.${index + 1}`,
9
+ x: side === "left" ? -1.35 : 1.35,
10
+ y: 2.8 - index * 0.2,
11
+ _facingDirection: side === "left" ? ("x-" as const) : ("x+" as const),
12
+ }))
13
+
14
+ // Reduced from the current @tscircuit/core input for an RP2040, then mirrored
15
+ // to cover both chip sides. The important details are the 0.2-unit pin pitch,
16
+ // 0.6-unit rail-label height, and a third distance-split member on each net.
17
+ // The reversed first pair preserves the MSP direction produced by the original
18
+ // multi-pin input (pin 10 to pin 1).
19
+ const inputProblem: InputProblem = {
20
+ chips: [
21
+ {
22
+ chipId: "U1",
23
+ center: { x: 0, y: 0 },
24
+ width: 1.9,
25
+ height: 6,
26
+ pins: [...createRp2040SidePins("left"), ...createRp2040SidePins("right")],
27
+ },
28
+ ],
29
+ directConnections: [],
30
+ netConnections: [
31
+ {
32
+ netId: "V3V3_LEFT",
33
+ pinIds: ["U1.left.10", "U1.left.1", "U1.left.22"],
34
+ netLabelWidth: 0.42,
35
+ netLabelHeight: 0.6,
36
+ },
37
+ {
38
+ netId: "V3V3_RIGHT",
39
+ pinIds: ["U1.right.10", "U1.right.1", "U1.right.22"],
40
+ netLabelWidth: 0.42,
41
+ netLabelHeight: 0.6,
42
+ },
43
+ ],
44
+ textBoxes: [
45
+ {
46
+ chipId: "U1",
47
+ center: { x: -0.83, y: 3.115 },
48
+ width: 0.36,
49
+ height: 0.25,
50
+ text: "U1",
51
+ },
52
+ ],
53
+ availableNetLabelOrientations: {
54
+ V3V3_LEFT: ["y+"],
55
+ V3V3_RIGHT: ["y+"],
56
+ },
57
+ maxMspPairDistance: 2.4,
58
+ }
59
+
60
+ test("places RP2040 rail labels above and outside both chip sides", () => {
61
+ const solver = new SchematicTracePipelineSolver(inputProblem)
62
+
63
+ solver.solve()
64
+
65
+ const outputLabels =
66
+ solver.netLabelNetLabelCollisionSolver!.getOutput().netLabelPlacements
67
+ const u1 = solver.inputProblem.chips.find((chip) => chip.chipId === "U1")!
68
+ const chipLeft = u1.center.x - u1.width / 2
69
+ const chipRight = u1.center.x + u1.width / 2
70
+
71
+ for (const side of ["left", "right"] as const) {
72
+ const netId = `V3V3_${side.toUpperCase()}`
73
+ const label = outputLabels.find(
74
+ (candidate) =>
75
+ candidate.netId === netId && candidate.pinIds.includes(`U1.${side}.1`),
76
+ )!
77
+ const connector = solver.availableNetOrientationSolver!.traces.find(
78
+ (trace) =>
79
+ trace.userNetId === netId &&
80
+ trace.mspPairId.startsWith("available-net-orientation-"),
81
+ )!
82
+ const [connectorSource, connectorTarget] = connector.tracePath
83
+ const labelLeft = label.center.x - label.width / 2
84
+ const labelRight = label.center.x + label.width / 2
85
+
86
+ expect(label.orientation).toBe("y+")
87
+ expect(label.anchorPoint.y).toBeCloseTo(2.8)
88
+ expect(connector.tracePath).toHaveLength(2)
89
+ expect(connectorSource!.y).toBeCloseTo(connectorTarget!.y)
90
+ expect(Math.abs(connectorSource!.x - connectorTarget!.x)).toBeLessThan(0.5)
91
+
92
+ if (side === "left") {
93
+ expect(labelRight).toBeLessThan(chipLeft)
94
+ expect(connectorTarget!.x).toBeLessThan(connectorSource!.x)
95
+ } else {
96
+ expect(labelLeft).toBeGreaterThan(chipRight)
97
+ expect(connectorTarget!.x).toBeGreaterThan(connectorSource!.x)
98
+ }
99
+ }
100
+
101
+ expect(solver).toMatchSolverSnapshot(import.meta.path)
102
+ })