@tscircuit/schematic-trace-solver 0.0.202 → 0.0.204
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.js +54 -7
- package/lib/solvers/TraceCleanupSolver/getInteriorShortcutPaths.ts +41 -0
- package/lib/solvers/TraceCleanupSolver/rerouteGeneratedNetLabelConnectorCrossings.ts +7 -0
- package/lib/solvers/TraceCleanupSolver/sameNetRailAlignment/getFixedLabelCoordinate.ts +17 -8
- package/lib/solvers/TraceElbowTransitionSimplificationSolver/TraceElbowTransitionSimplificationSolver.ts +25 -3
- package/package.json +1 -1
- package/site/SchematicTracePipelineSolver/repro-smart-lock-ble-module.page.tsx +7 -0
- package/tests/bug-reports/bug-report-20260706T213649Z/__snapshots__/bug-report-20260706T213649Z.snap.svg +78 -60
- package/tests/bug-reports/bug-report-20260707T134722Z/__snapshots__/bug-report-20260707T134722Z.snap.svg +62 -62
- package/tests/bug-reports/bug-report-20260708T055430Z/__snapshots__/bug-report-20260708T055430Z.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-20260728T144234Z/__snapshots__/bug-report-20260728T144234Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260901T055358Z/__snapshots__/bug-report-20260901T055358Z.snap.svg +10 -10
- package/tests/bug-reports/bug-report-20260905T041712Z/__snapshots__/bug-report-20260905T041712Z.snap.svg +10 -10
- package/tests/bug-reports/bug-report-20260907T110144Z/__snapshots__/bug-report-20260907T110144Z.snap.svg +9 -9
- package/tests/bug-reports/bug-report-20260907T145640Z/__snapshots__/bug-report-20260907T145640Z.snap.svg +8 -8
- package/tests/bug-reports/bug-report-20260911T195723Z/__snapshots__/bug-report-20260911T195723Z.snap.svg +19 -19
- package/tests/bug-reports/bug-report-20260916T054012Z/__snapshots__/bug-report-20260916T054012Z.snap.svg +292 -292
- package/tests/examples/__snapshots__/example30.snap.svg +123 -123
- package/tests/repros/__snapshots__/board-1273-trace-overlap-cycle.snap.svg +18 -18
- package/tests/repros/__snapshots__/board-15984-same-net-junction.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-am3352-06-boot.snap.svg +448 -0
- package/tests/repros/__snapshots__/repro-am3352-sheet3-power-rails.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-hub-usb-sheet.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-ina237-current-monitor.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-pmp11282-isolated-dcdc.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-robot-controller-imu-tof.snap.svg +7 -7
- package/tests/repros/__snapshots__/repro-smart-lock-ble-module.snap.svg +465 -0
- package/tests/repros/__snapshots__/repro-tida010076-page02.snap.svg +10 -10
- package/tests/repros/assets/repro-am3352-06-boot.input.json +1875 -0
- package/tests/repros/assets/repro-smart-lock-ble-module.input.json +2183 -0
- package/tests/repros/repro-am3352-06-boot.test.ts +43 -0
- package/tests/repros/repro-smart-lock-ble-module.test.ts +69 -0
- package/tests/solvers/TraceCleanupSolver/alignSameNetRails-fixed-backbone.test.ts +135 -0
- package/tests/solvers/TraceCleanupSolver/reroute-generated-net-label-connector-crossings.test.ts +49 -0
- package/tests/solvers/TraceElbowTransitionSimplificationSolver/interior-staircase.test.ts +146 -0
|
@@ -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
|
+
})
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { isPathCollidingWithObstacles } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/collisions"
|
|
3
|
+
import { getObstacleRects } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/rect"
|
|
4
|
+
import { SchematicTracePipelineSolver } from "lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver"
|
|
5
|
+
import { detectTraceLabelOverlap } from "lib/solvers/TraceLabelOverlapAvoidanceSolver/detectTraceLabelOverlap"
|
|
6
|
+
import type { InputProblem } from "lib/types/InputProblem"
|
|
7
|
+
import "tests/fixtures/matcher"
|
|
8
|
+
import input from "./assets/repro-smart-lock-ble-module.input.json"
|
|
9
|
+
|
|
10
|
+
// Full ble_module sheet from imrishabh18/smart-lock v0.0.1.
|
|
11
|
+
// Reconstructed from deployed Circuit JSON with current core routing defaults.
|
|
12
|
+
test("repro smart-lock BLE module schematic sheet", async () => {
|
|
13
|
+
const solver = new SchematicTracePipelineSolver(
|
|
14
|
+
structuredClone(input) as unknown as InputProblem,
|
|
15
|
+
{ hideRatsNet: true },
|
|
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 supplyLabel = netLabelPlacements.find((label) =>
|
|
25
|
+
label.mspConnectionPairIds.includes(
|
|
26
|
+
"schematic_port_246-schematic_port_243",
|
|
27
|
+
),
|
|
28
|
+
)!
|
|
29
|
+
// C99, C104, C103, and C102 must share C101's labeled VDDS rail.
|
|
30
|
+
for (const traceId of [
|
|
31
|
+
"schematic_port_244-schematic_port_246",
|
|
32
|
+
"schematic_port_248-schematic_port_246",
|
|
33
|
+
"schematic_port_250-schematic_port_248",
|
|
34
|
+
"schematic_port_252-schematic_port_250",
|
|
35
|
+
]) {
|
|
36
|
+
const trace = traces.find((trace) => trace.mspPairId === traceId)!
|
|
37
|
+
expect(trace.tracePath[1]!.y).toBeCloseTo(supplyLabel.anchorPoint.y)
|
|
38
|
+
expect(trace.tracePath[2]!.y).toBeCloseTo(supplyLabel.anchorPoint.y)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// The C92–L34 ground trace needs one offset around U1's label column.
|
|
42
|
+
const groundTrace = traces.find(
|
|
43
|
+
(trace) => trace.mspPairId === "schematic_port_291-schematic_port_297",
|
|
44
|
+
)!
|
|
45
|
+
const path = groundTrace.tracePath
|
|
46
|
+
expect(path).toHaveLength(6)
|
|
47
|
+
expect(path[2]!.x).toBeCloseTo(path[3]!.x)
|
|
48
|
+
expect(path[3]!.y).toBeCloseTo(path[4]!.y)
|
|
49
|
+
for (const [endpoint, neighbor, pin] of [
|
|
50
|
+
[path[0]!, path[1]!, groundTrace.pins[0]!],
|
|
51
|
+
[path.at(-1)!, path.at(-2)!, groundTrace.pins[1]!],
|
|
52
|
+
] as const) {
|
|
53
|
+
expect(endpoint.x).toBeCloseTo(pin.x)
|
|
54
|
+
expect(endpoint.y).toBeCloseTo(pin.y)
|
|
55
|
+
expect(neighbor.x).toBeCloseTo(endpoint.x)
|
|
56
|
+
expect(neighbor.y).toBeLessThan(endpoint.y)
|
|
57
|
+
}
|
|
58
|
+
expect(
|
|
59
|
+
isPathCollidingWithObstacles(path, getObstacleRects(solver.inputProblem)),
|
|
60
|
+
).toBe(false)
|
|
61
|
+
expect(
|
|
62
|
+
detectTraceLabelOverlap({
|
|
63
|
+
traces: [groundTrace],
|
|
64
|
+
netLabels: netLabelPlacements,
|
|
65
|
+
}),
|
|
66
|
+
).toHaveLength(0)
|
|
67
|
+
|
|
68
|
+
await expect(solver).toMatchSolverSnapshot(import.meta.path)
|
|
69
|
+
})
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import type { NetLabelPlacement } from "lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver"
|
|
3
|
+
import type { InputProblem } from "lib/types/InputProblem"
|
|
4
|
+
import { align, createTrace } from "./fixtures/alignSameNetRails"
|
|
5
|
+
|
|
6
|
+
const createFixture = () => {
|
|
7
|
+
const firstPin = {
|
|
8
|
+
pinId: "C1.1",
|
|
9
|
+
chipId: "C1",
|
|
10
|
+
x: -2,
|
|
11
|
+
y: 0,
|
|
12
|
+
_facingDirection: "y+" as const,
|
|
13
|
+
}
|
|
14
|
+
const sharedPin = {
|
|
15
|
+
pinId: "C2.1",
|
|
16
|
+
chipId: "C2",
|
|
17
|
+
x: 0,
|
|
18
|
+
y: 0,
|
|
19
|
+
_facingDirection: "y+" as const,
|
|
20
|
+
}
|
|
21
|
+
const supplyPin = {
|
|
22
|
+
pinId: "F1.1",
|
|
23
|
+
chipId: "F1",
|
|
24
|
+
x: 1,
|
|
25
|
+
y: 3,
|
|
26
|
+
_facingDirection: "x-" as const,
|
|
27
|
+
}
|
|
28
|
+
const problem: InputProblem = {
|
|
29
|
+
maxMspPairDistance: 2.4,
|
|
30
|
+
chips: [
|
|
31
|
+
{
|
|
32
|
+
chipId: "C1",
|
|
33
|
+
center: { x: -2, y: -0.5 },
|
|
34
|
+
width: 0.8,
|
|
35
|
+
height: 1,
|
|
36
|
+
pins: [firstPin],
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
chipId: "C2",
|
|
40
|
+
center: { x: 0, y: -0.5 },
|
|
41
|
+
width: 0.8,
|
|
42
|
+
height: 1,
|
|
43
|
+
pins: [sharedPin],
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
chipId: "F1",
|
|
47
|
+
center: { x: 1.5, y: 3 },
|
|
48
|
+
width: 1,
|
|
49
|
+
height: 0.8,
|
|
50
|
+
pins: [supplyPin],
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
directConnections: [],
|
|
54
|
+
netConnections: [],
|
|
55
|
+
availableNetLabelOrientations: {},
|
|
56
|
+
}
|
|
57
|
+
const branch = createTrace(
|
|
58
|
+
"branch",
|
|
59
|
+
[
|
|
60
|
+
{ x: -2, y: 0 },
|
|
61
|
+
{ x: -2, y: 1 },
|
|
62
|
+
{ x: 0, y: 1 },
|
|
63
|
+
{ x: 0, y: 0 },
|
|
64
|
+
],
|
|
65
|
+
[firstPin, sharedPin],
|
|
66
|
+
)
|
|
67
|
+
const backbone = createTrace(
|
|
68
|
+
"backbone",
|
|
69
|
+
[
|
|
70
|
+
{ x: 0, y: 0 },
|
|
71
|
+
{ x: 0, y: 2 },
|
|
72
|
+
{ x: 0.5, y: 2 },
|
|
73
|
+
{ x: 0.5, y: 3 },
|
|
74
|
+
{ x: 1, y: 3 },
|
|
75
|
+
],
|
|
76
|
+
[sharedPin, supplyPin],
|
|
77
|
+
)
|
|
78
|
+
const label: NetLabelPlacement = {
|
|
79
|
+
globalConnNetId: "power-net",
|
|
80
|
+
netId: "POWER",
|
|
81
|
+
mspConnectionPairIds: ["backbone"],
|
|
82
|
+
pinIds: backbone.pinIds,
|
|
83
|
+
orientation: "y+",
|
|
84
|
+
anchorPoint: { x: 0, y: 2 },
|
|
85
|
+
center: { x: 0, y: 2.1 },
|
|
86
|
+
width: 0.4,
|
|
87
|
+
height: 0.2,
|
|
88
|
+
}
|
|
89
|
+
return { problem, branch, backbone, label }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
test("aligns a branch to a labeled backbone without moving its elbows", () => {
|
|
93
|
+
const { problem, branch, backbone, label } = createFixture()
|
|
94
|
+
const result = align([branch, backbone], {
|
|
95
|
+
inputProblem: problem,
|
|
96
|
+
netLabelPlacements: [label],
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
expect(result.traces[0]!.tracePath).toEqual([
|
|
100
|
+
{ x: -2, y: 0 },
|
|
101
|
+
{ x: -2, y: 2 },
|
|
102
|
+
{ x: 0, y: 2 },
|
|
103
|
+
{ x: 0, y: 0 },
|
|
104
|
+
])
|
|
105
|
+
expect(result.traces[1]).toEqual(backbone)
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
test("keeps the branch below an obstacle on the fixed backbone coordinate", () => {
|
|
109
|
+
const { problem, branch, backbone, label } = createFixture()
|
|
110
|
+
problem.chips.push({
|
|
111
|
+
chipId: "obstacle",
|
|
112
|
+
center: { x: -1, y: 2 },
|
|
113
|
+
width: 0.4,
|
|
114
|
+
height: 0.4,
|
|
115
|
+
pins: [],
|
|
116
|
+
})
|
|
117
|
+
const result = align([branch, backbone], {
|
|
118
|
+
inputProblem: problem,
|
|
119
|
+
netLabelPlacements: [label],
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
expect(result.traces).toEqual([branch, backbone])
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
test("does not pull a multi-turn backbone toward a label on a different coordinate", () => {
|
|
126
|
+
const { problem, branch, backbone, label } = createFixture()
|
|
127
|
+
label.anchorPoint.y = 1.5
|
|
128
|
+
label.center.y = 1.6
|
|
129
|
+
const result = align([branch, backbone], {
|
|
130
|
+
inputProblem: problem,
|
|
131
|
+
netLabelPlacements: [label],
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
expect(result.traces).toEqual([branch, backbone])
|
|
135
|
+
})
|
package/tests/solvers/TraceCleanupSolver/reroute-generated-net-label-connector-crossings.test.ts
CHANGED
|
@@ -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
|
+
)
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { expect, test } from "bun:test"
|
|
2
|
+
import { getPathLength } from "lib/solvers/Example28Solver/geometry"
|
|
3
|
+
import type { NetLabelPlacement } from "lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver"
|
|
4
|
+
import { TraceElbowTransitionSimplificationSolver } from "lib/solvers/TraceElbowTransitionSimplificationSolver/TraceElbowTransitionSimplificationSolver"
|
|
5
|
+
import type { InputProblem } from "lib/types/InputProblem"
|
|
6
|
+
import { createTrace } from "../TraceCleanupSolver/fixtures/alignSameNetRails"
|
|
7
|
+
|
|
8
|
+
const createFixture = () => {
|
|
9
|
+
const path = [
|
|
10
|
+
{ x: 5, y: 0 },
|
|
11
|
+
{ x: 5, y: -1 },
|
|
12
|
+
{ x: 2.5, y: -1 },
|
|
13
|
+
{ x: 2.5, y: 2 },
|
|
14
|
+
{ x: 2, y: 2 },
|
|
15
|
+
{ x: 2, y: 3 },
|
|
16
|
+
{ x: 1, y: 3 },
|
|
17
|
+
{ x: 1, y: 4 },
|
|
18
|
+
]
|
|
19
|
+
const trace = createTrace("rerouted", path, [
|
|
20
|
+
{ pinId: "C1.1", chipId: "C1", x: 5, y: 0, _facingDirection: "y-" },
|
|
21
|
+
{ pinId: "L1.1", chipId: "L1", x: 1, y: 4, _facingDirection: "y-" },
|
|
22
|
+
])
|
|
23
|
+
const labels: NetLabelPlacement[] = [
|
|
24
|
+
{
|
|
25
|
+
globalConnNetId: "signal",
|
|
26
|
+
netId: "SIGNAL",
|
|
27
|
+
mspConnectionPairIds: [],
|
|
28
|
+
pinIds: [],
|
|
29
|
+
orientation: "x+",
|
|
30
|
+
anchorPoint: { x: 0.5, y: 0.7 },
|
|
31
|
+
center: { x: 1.45, y: 0.7 },
|
|
32
|
+
width: 1.9,
|
|
33
|
+
height: 2.4,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
globalConnNetId: "signal2",
|
|
37
|
+
netId: "SIGNAL2",
|
|
38
|
+
mspConnectionPairIds: [],
|
|
39
|
+
pinIds: [],
|
|
40
|
+
orientation: "x+",
|
|
41
|
+
anchorPoint: { x: 0.5, y: 2.45 },
|
|
42
|
+
center: { x: 1.2, y: 2.45 },
|
|
43
|
+
width: 1.4,
|
|
44
|
+
height: 0.9,
|
|
45
|
+
},
|
|
46
|
+
]
|
|
47
|
+
const problem: InputProblem = {
|
|
48
|
+
chips: [],
|
|
49
|
+
directConnections: [],
|
|
50
|
+
netConnections: [],
|
|
51
|
+
availableNetLabelOrientations: {},
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
inputProblem: problem,
|
|
55
|
+
traces: [trace],
|
|
56
|
+
completedReroutes: [
|
|
57
|
+
{
|
|
58
|
+
initialTrace: trace,
|
|
59
|
+
reroutedTracePath: path,
|
|
60
|
+
label: labels[0]!,
|
|
61
|
+
detourCount: 0,
|
|
62
|
+
},
|
|
63
|
+
],
|
|
64
|
+
netLabelPlacements: labels,
|
|
65
|
+
paddingBuffer: 0.1,
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
test("merges successive label detours without changing length or terminal directions", () => {
|
|
70
|
+
const input = createFixture()
|
|
71
|
+
const solver = new TraceElbowTransitionSimplificationSolver(input)
|
|
72
|
+
solver.solve()
|
|
73
|
+
const path = solver.getOutput().traces[0]!.tracePath
|
|
74
|
+
|
|
75
|
+
expect(path).toEqual([
|
|
76
|
+
{ x: 5, y: 0 },
|
|
77
|
+
{ x: 5, y: -1 },
|
|
78
|
+
{ x: 2.5, y: -1 },
|
|
79
|
+
{ x: 2.5, y: 3 },
|
|
80
|
+
{ x: 1, y: 3 },
|
|
81
|
+
{ x: 1, y: 4 },
|
|
82
|
+
])
|
|
83
|
+
expect(getPathLength(path)).toBeCloseTo(
|
|
84
|
+
getPathLength(input.traces[0]!.tracePath),
|
|
85
|
+
)
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
test.each([
|
|
89
|
+
"component",
|
|
90
|
+
"label",
|
|
91
|
+
"parallel_trace",
|
|
92
|
+
"crossing_trace",
|
|
93
|
+
"anchor",
|
|
94
|
+
] as const)("preserves a necessary staircase blocked by %s", (blocker) => {
|
|
95
|
+
const input = createFixture()
|
|
96
|
+
if (blocker === "component") {
|
|
97
|
+
input.inputProblem.chips.push({
|
|
98
|
+
chipId: "obstacle",
|
|
99
|
+
center: { x: 2.5, y: 2.5 },
|
|
100
|
+
width: 0.2,
|
|
101
|
+
height: 0.4,
|
|
102
|
+
pins: [],
|
|
103
|
+
})
|
|
104
|
+
} else if (blocker === "parallel_trace" || blocker === "crossing_trace") {
|
|
105
|
+
const path =
|
|
106
|
+
blocker === "parallel_trace"
|
|
107
|
+
? [
|
|
108
|
+
{ x: 2.5, y: 2.2 },
|
|
109
|
+
{ x: 2.5, y: 2.8 },
|
|
110
|
+
]
|
|
111
|
+
: [
|
|
112
|
+
{ x: 2.3, y: 2.5 },
|
|
113
|
+
{ x: 2.7, y: 2.5 },
|
|
114
|
+
]
|
|
115
|
+
input.traces.push(
|
|
116
|
+
createTrace(
|
|
117
|
+
"foreign",
|
|
118
|
+
path,
|
|
119
|
+
[
|
|
120
|
+
{ pinId: "X1.1", chipId: "X1", ...path[0]! },
|
|
121
|
+
{ pinId: "X2.1", chipId: "X2", ...path[1]! },
|
|
122
|
+
],
|
|
123
|
+
"foreign",
|
|
124
|
+
),
|
|
125
|
+
)
|
|
126
|
+
} else {
|
|
127
|
+
const x = blocker === "anchor" ? 2 : 2.5
|
|
128
|
+
input.netLabelPlacements.push({
|
|
129
|
+
globalConnNetId: blocker === "anchor" ? "power-net" : "foreign",
|
|
130
|
+
netId: "BLOCKER",
|
|
131
|
+
mspConnectionPairIds: ["rerouted"],
|
|
132
|
+
pinIds: [],
|
|
133
|
+
orientation: "x+",
|
|
134
|
+
anchorPoint: { x, y: 2.5 },
|
|
135
|
+
center: { x: x + 0.1, y: 2.5 },
|
|
136
|
+
width: 0.2,
|
|
137
|
+
height: 0.4,
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
const solver = new TraceElbowTransitionSimplificationSolver(input)
|
|
141
|
+
solver.solve()
|
|
142
|
+
|
|
143
|
+
expect(solver.getOutput().traces[0]!.tracePath).toEqual(
|
|
144
|
+
input.traces[0]!.tracePath,
|
|
145
|
+
)
|
|
146
|
+
})
|