@tscircuit/schematic-trace-solver 0.0.201 → 0.0.203

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,82 @@
1
+ {
2
+ "chips": [
3
+ {
4
+ "chipId": "J1",
5
+ "center": { "x": -13, "y": 6 },
6
+ "width": 1.3,
7
+ "height": 0.4,
8
+ "pins": [
9
+ {
10
+ "pinId": "J1.1",
11
+ "x": -14.05,
12
+ "y": 6,
13
+ "_facingDirection": "x-"
14
+ }
15
+ ]
16
+ },
17
+ {
18
+ "chipId": "F1",
19
+ "symbolName": "fuse_horz",
20
+ "center": { "x": -10.17, "y": 6.115 },
21
+ "width": 0.74,
22
+ "height": 0.39,
23
+ "pins": [
24
+ {
25
+ "pinId": "F1.1",
26
+ "x": -10.4,
27
+ "y": 6,
28
+ "_facingDirection": "x-"
29
+ },
30
+ {
31
+ "pinId": "F1.2",
32
+ "x": -9.6,
33
+ "y": 6,
34
+ "_facingDirection": "x+"
35
+ }
36
+ ]
37
+ },
38
+ {
39
+ "chipId": "RV1",
40
+ "symbolName": "varistor_horz",
41
+ "center": { "x": -10.195, "y": 3.615 },
42
+ "width": 0.79,
43
+ "height": 0.47,
44
+ "pins": [
45
+ {
46
+ "pinId": "RV1.1",
47
+ "x": -10.4,
48
+ "y": 3.5,
49
+ "_facingDirection": "x-"
50
+ },
51
+ {
52
+ "pinId": "RV1.2",
53
+ "x": -9.6,
54
+ "y": 3.5,
55
+ "_facingDirection": "x+"
56
+ }
57
+ ]
58
+ }
59
+ ],
60
+ "directConnections": [
61
+ {
62
+ "netId": "LINE",
63
+ "pinIds": ["J1.1", "F1.1"]
64
+ },
65
+ {
66
+ "netId": "LINE_FUSED",
67
+ "pinIds": ["F1.2", "RV1.1"]
68
+ }
69
+ ],
70
+ "netConnections": [
71
+ {
72
+ "netId": "NEUTRAL",
73
+ "netLabelText": "NEUTRAL",
74
+ "netLabelWidth": 0.84,
75
+ "pinIds": ["RV1.2"]
76
+ }
77
+ ],
78
+ "availableNetLabelOrientations": {
79
+ "NEUTRAL": ["x+"]
80
+ },
81
+ "maxMspPairDistance": 100
82
+ }
@@ -0,0 +1,43 @@
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 { tracePathContainsPoint } from "lib/solvers/RailNetLabelCornerPlacementSolver/geometry"
5
+ import { findPerpendicularPathCrossings } from "lib/solvers/TraceCleanupSolver/sub-solver/findIntersectionsWithObstacles"
6
+ import "tests/fixtures/matcher"
7
+ import input from "./assets/repro-am3352-06-boot.input.json"
8
+
9
+ // Full sheet from am3352-dev-board-4layer-dogbone.json; routing uses core defaults.
10
+ test("repro complete AM3352 06-Boot sheet", async () => {
11
+ const problem = structuredClone(input) as InputProblem
12
+ const solver = new SchematicTracePipelineSolver(problem, {
13
+ hideRatsNet: true,
14
+ })
15
+ solver.solve()
16
+ expect(solver.solved).toBe(true)
17
+ expect(solver.failed).toBe(false)
18
+ const { traces, inlineNetLabelPlacements } =
19
+ solver.netLabelToTraceSolver!.getOutput()
20
+ for (const netId of ["BOOT_SEL1", "BOOT_SEL2", "BOOT_SEL3"]) {
21
+ const trace = traces.find((trace) => trace.userNetId === netId)!
22
+ expect(trace).toBeDefined()
23
+ expect(trace.tracePath).toHaveLength(4)
24
+ expect(trace.tracePath[1]!.y).toBe(trace.tracePath[0]!.y)
25
+ expect(trace.tracePath[2]!.y).toBe(trace.tracePath[3]!.y)
26
+ const label = inlineNetLabelPlacements.find(
27
+ (label) => label.globalConnNetId === trace.globalConnNetId,
28
+ )!
29
+ expect(label).toBeDefined()
30
+ expect(tracePathContainsPoint(trace.tracePath, label.anchorPoint)).toBe(
31
+ true,
32
+ )
33
+ for (const otherTrace of traces) {
34
+ if (otherTrace.globalConnNetId === trace.globalConnNetId) continue
35
+ expect(
36
+ findPerpendicularPathCrossings(trace.tracePath, otherTrace.tracePath, {
37
+ includeTerminalSegments: true,
38
+ }),
39
+ ).toEqual([])
40
+ }
41
+ }
42
+ await expect(solver).toMatchSolverSnapshot(import.meta.path)
43
+ })
@@ -1,4 +1,5 @@
1
1
  import { expect, test } from "bun:test"
2
+ import { getOutputLabelCollisions } from "lib/solvers/InlineNetLabelSolver/getOutputLabelCollisions"
2
3
  import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
3
4
  import "tests/fixtures/matcher"
4
5
  import inputProblem from "./assets/repro-mouse-switch-ground-unnecessary-jog.input.json"
@@ -11,5 +12,19 @@ test("repro unnecessary jog in mouse switch ground trunk", () => {
11
12
 
12
13
  solver.solve()
13
14
 
15
+ const inlineOutput = solver.inlineNetLabelSolver!.getOutput()
16
+ const groundLabel = inlineOutput.netLabelPlacements.find(
17
+ (label) => label.netId === "GND",
18
+ )
19
+ expect(groundLabel?.orientation).toBe("y-")
20
+ expect(
21
+ inlineOutput.inlineNetLabelPlacements.some(
22
+ (label) => label.netId === "RIGHT",
23
+ ),
24
+ ).toBe(true)
25
+ expect(
26
+ inlineOutput.netLabelPlacements.some((label) => label.netId === "RIGHT"),
27
+ ).toBe(false)
28
+ expect(getOutputLabelCollisions(inlineOutput)).toEqual([])
14
29
  expect(solver).toMatchSolverSnapshot(import.meta.path)
15
30
  })
@@ -0,0 +1,21 @@
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 inputProblemJson from "./assets/repro-trace-endpoints-stop-at-component-boundary.input.json"
6
+
7
+ const inputProblem: InputProblem = JSON.parse(JSON.stringify(inputProblemJson))
8
+
9
+ // F1 and RV1 have ports inside their text-expanded component bounds. The
10
+ // routed traces currently stop at the lower bounds instead of reaching the
11
+ // original left-facing port coordinates.
12
+ test("trace endpoints stop at component boundaries before reaching target ports", () => {
13
+ const solver = new SchematicTracePipelineSolver(inputProblem, {
14
+ hideRatsNet: true,
15
+ })
16
+
17
+ solver.solve()
18
+
19
+ expect(solver.schematicTraceLinesSolver!.solvedTracePaths).toHaveLength(2)
20
+ expect(solver).toMatchSolverSnapshot(import.meta.path)
21
+ })
@@ -158,3 +158,52 @@ test("allows crossings between generated label connectors", () => {
158
158
  expect(result.reroutedTraceCount).toBe(0)
159
159
  expect(result.traces).toEqual([connectorTrace, otherConnector])
160
160
  })
161
+
162
+ test.each([false, true])(
163
+ "removes the old loop when rerouting a connector crossing (reversed: %s)",
164
+ (reversed) => {
165
+ let tracePath = [
166
+ { x: 0, y: 0 },
167
+ { x: 1, y: 0 },
168
+ { x: 1, y: 3 },
169
+ { x: 4, y: 3 },
170
+ { x: 4, y: -3 },
171
+ { x: 0, y: -3 },
172
+ ]
173
+ if (reversed) tracePath = tracePath.toReversed()
174
+ const trace = makeTrace({
175
+ mspPairId: "loop",
176
+ globalConnNetId: "signal",
177
+ pinIds: ["a", "b"],
178
+ tracePath,
179
+ })
180
+ const connector = makeTrace({
181
+ mspPairId: "connector",
182
+ globalConnNetId: "power",
183
+ pinIds: ["c"],
184
+ tracePath: [
185
+ { x: 0, y: 1 },
186
+ { x: 2, y: 1 },
187
+ ],
188
+ })
189
+ const result = rerouteGeneratedNetLabelConnectorCrossings({
190
+ inputProblem,
191
+ traces: [trace, connector],
192
+ netLabelPlacements: [],
193
+ mergedLabelNetIdMap: {},
194
+ clearance: 0.1,
195
+ connectorTraceIds: new Set([connector.mspPairId]),
196
+ })
197
+ const path = result.traces[0]!.tracePath
198
+ expect(result.reroutedTraceCount).toBe(1)
199
+ expect(path).toHaveLength(4)
200
+ expect(path[0]).toEqual(tracePath[0])
201
+ expect(path.at(-1)).toEqual(tracePath.at(-1))
202
+ expect(getPathLength(path)).toBeLessThan(getPathLength(tracePath))
203
+ expect(
204
+ findPerpendicularPathCrossings(path, connector.tracePath, {
205
+ includeTerminalSegments: true,
206
+ }),
207
+ ).toEqual([])
208
+ },
209
+ )