@tscircuit/schematic-trace-solver 0.0.40 → 0.0.42

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.
Files changed (57) hide show
  1. package/dist/index.d.ts +155 -9
  2. package/dist/index.js +998 -479
  3. package/lib/solvers/LongDistancePairSolver/LongDistancePairSolver.ts +238 -0
  4. package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +61 -26
  5. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/TraceLabelOverlapAvoidanceSolver.ts +94 -192
  6. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/rerouteCollidingTrace.ts +13 -24
  7. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/LabelMergingSolver/LabelMergingSolver.ts +205 -0
  8. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/OverlapAvoidanceStepSolver/OverlapAvoidanceStepSolver.ts +144 -0
  9. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/SingleOverlapSolver/SingleOverlapSolver.ts +117 -0
  10. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver/TraceCleanupSolver.ts +132 -0
  11. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{balanceLShapes.ts → sub-solvers/TraceCleanupSolver/balanceLShapes.ts} +12 -10
  12. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{hasCollisions.ts → sub-solvers/TraceCleanupSolver/hasCollisions.ts} +1 -1
  13. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{hasCollisionsWithLabels.ts → sub-solvers/TraceCleanupSolver/hasCollisionsWithLabels.ts} +1 -1
  14. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{minimizeTurnsWithFilteredLabels.ts → sub-solvers/TraceCleanupSolver/minimizeTurnsWithFilteredLabels.ts} +6 -6
  15. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{simplifyPath.ts → sub-solvers/TraceCleanupSolver/simplifyPath.ts} +1 -1
  16. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{turnMinimization.ts → sub-solvers/TraceCleanupSolver/turnMinimization.ts} +0 -2
  17. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/tryFourPointDetour.ts +104 -0
  18. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/trySnipAndReconnect.ts +24 -154
  19. package/lib/utils/does-trace-overlap-with-existing-traces.ts +33 -0
  20. package/package.json +1 -1
  21. package/site/examples/example25.page.tsx +4 -0
  22. package/tests/assets/1.input.json +379 -0
  23. package/tests/assets/2.input.json +330 -0
  24. package/tests/assets/3.input.json +388 -0
  25. package/tests/assets/MergedNetLabelObstacles.test.input.json +154 -0
  26. package/tests/assets/OverlapAvoidanceStepSolver.test.input.json +682 -0
  27. package/tests/assets/SingleOverlapSolver.test.input.json +170 -0
  28. package/tests/assets/TraceCleanupSolver.test.input.json +216 -0
  29. package/tests/assets/TraceLabelOverlapAvoidanceSolver.test.input.json +424 -0
  30. package/tests/assets/example25.json +96 -0
  31. package/tests/examples/__snapshots__/example03.snap.svg +67 -76
  32. package/tests/examples/__snapshots__/example10.snap.svg +24 -30
  33. package/tests/examples/__snapshots__/example13.snap.svg +81 -84
  34. package/tests/examples/__snapshots__/example15.snap.svg +5 -8
  35. package/tests/examples/__snapshots__/example21.snap.svg +68 -74
  36. package/tests/examples/__snapshots__/example25.snap.svg +3 -3
  37. package/tests/examples/__snapshots__/example26.snap.svg +3 -3
  38. package/tests/examples/__snapshots__/example28.snap.svg +273 -0
  39. package/tests/examples/example28.test.ts +13 -0
  40. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/TraceLabelOverlapAvoidanceSolver.test.ts +18 -0
  41. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/__snapshots__/TraceLabelOverlapAvoidanceSolver.snap.svg +243 -0
  42. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/__snapshots__/renderComparisonView01.snap.svg +223 -0
  43. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/__snapshots__/renderComparisonView02.snap.svg +205 -0
  44. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/__snapshots__/renderComparisonView03.snap.svg +184 -0
  45. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/renderComparisonView01.test.ts +29 -0
  46. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/renderComparisonView02.test.ts +27 -0
  47. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/renderComparisonView03.test.ts +39 -0
  48. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/MergedNetLabelObstacles.test.ts +14 -0
  49. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/OverlapAvoidanceStepSolver.test.ts +20 -0
  50. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/SingleOverlapSolver.test.ts +10 -0
  51. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/TraceCleanupSolver.test.ts +19 -0
  52. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/MergedNetLabelObstacles.snap.svg +140 -0
  53. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/OverlapAvoidanceStepSolver.snap.svg +216 -0
  54. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/SingleOverlapSolver.snap.svg +125 -0
  55. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/TraceCleanupSolver.snap.svg +119 -0
  56. /package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{countTurns.ts → sub-solvers/TraceCleanupSolver/countTurns.ts} +0 -0
  57. /package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{tryConnectPoints.ts → sub-solvers/TraceCleanupSolver/tryConnectPoints.ts} +0 -0
@@ -0,0 +1,238 @@
1
+ import { getConnectivityMapsFromInputProblem } from "lib/solvers/MspConnectionPairSolver/getConnectivityMapFromInputProblem"
2
+ import type { MspConnectionPair } from "lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver"
3
+ import type {
4
+ InputProblem,
5
+ InputPin,
6
+ PinId,
7
+ InputChip,
8
+ } from "lib/types/InputProblem"
9
+ import { BaseSolver } from "../BaseSolver/BaseSolver"
10
+ import { SchematicTraceSingleLineSolver2 } from "../SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/SchematicTraceSingleLineSolver2"
11
+ import { doesTraceOverlapWithExistingTraces } from "lib/utils/does-trace-overlap-with-existing-traces"
12
+ import { visualizeInputProblem } from "../SchematicTracePipelineSolver/visualizeInputProblem"
13
+ import type { SolvedTracePath } from "../SchematicTraceLinesSolver/SchematicTraceLinesSolver"
14
+ import type { ConnectivityMap } from "connectivity-map"
15
+
16
+ const NEAREST_NEIGHBOR_COUNT = 3
17
+
18
+ const distance = (p1: InputPin, p2: InputPin) => {
19
+ return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2))
20
+ }
21
+
22
+ export class LongDistancePairSolver extends BaseSolver {
23
+ public solvedLongDistanceTraces: SolvedTracePath[] = []
24
+ private queuedCandidatePairs: Array<
25
+ [InputPin & { chipId: string }, InputPin & { chipId: string }]
26
+ > = []
27
+ private currentCandidatePair:
28
+ | [InputPin & { chipId: string }, InputPin & { chipId: string }]
29
+ | null = null
30
+ private subSolver: SchematicTraceSingleLineSolver2 | null = null
31
+ private chipMap: Record<string, InputChip> = {}
32
+ private inputProblem: InputProblem
33
+ private netConnMap: ConnectivityMap
34
+ private newlyConnectedPinIds = new Set<PinId>()
35
+ private allSolvedTraces: SolvedTracePath[] = []
36
+
37
+ constructor(
38
+ private params: {
39
+ inputProblem: InputProblem
40
+ alreadySolvedTraces: SolvedTracePath[]
41
+ primaryMspConnectionPairs: MspConnectionPair[]
42
+ },
43
+ ) {
44
+ super()
45
+
46
+ const { inputProblem, primaryMspConnectionPairs, alreadySolvedTraces } =
47
+ this.params
48
+
49
+ this.inputProblem = inputProblem
50
+ this.allSolvedTraces = [...alreadySolvedTraces]
51
+
52
+ // 1. Create initial maps and sets for efficient lookup
53
+ const primaryConnectedPinIds = new Set<PinId>()
54
+ for (const pair of primaryMspConnectionPairs) {
55
+ primaryConnectedPinIds.add(pair.pins[0].pinId)
56
+ primaryConnectedPinIds.add(pair.pins[1].pinId)
57
+ }
58
+
59
+ const { netConnMap } = getConnectivityMapsFromInputProblem(inputProblem)
60
+ this.netConnMap = netConnMap
61
+ const pinMap = new Map<PinId, InputPin & { chipId: string }>()
62
+ for (const chip of inputProblem.chips) {
63
+ this.chipMap[chip.chipId] = chip
64
+ for (const pin of chip.pins) {
65
+ pinMap.set(pin.pinId, { ...pin, chipId: chip.chipId })
66
+ }
67
+ }
68
+
69
+ // 2. Generate candidate pairs using N-Nearest-Neighbors approach
70
+ const candidatePairs: Array<
71
+ [InputPin & { chipId: string }, InputPin & { chipId: string }]
72
+ > = []
73
+ const addedPairKeys = new Set<string>()
74
+
75
+ for (const netId of Object.keys(netConnMap.netMap)) {
76
+ const allPinIdsInNet = netConnMap.getIdsConnectedToNet(netId)
77
+ if (allPinIdsInNet.length < 2) continue
78
+
79
+ const unconnectedPinIds = allPinIdsInNet.filter(
80
+ (pinId) => !primaryConnectedPinIds.has(pinId),
81
+ )
82
+
83
+ for (const unconnectedPinId of unconnectedPinIds) {
84
+ const sourcePin = pinMap.get(unconnectedPinId)
85
+ if (!sourcePin) continue
86
+
87
+ const neighbors = allPinIdsInNet
88
+ .filter((otherPinId) => otherPinId !== unconnectedPinId)
89
+ .flatMap((otherPinId) => {
90
+ const targetPin = pinMap.get(otherPinId)
91
+ if (!targetPin) return [] // Gracefully handle missing pins
92
+ return [
93
+ {
94
+ pin: targetPin,
95
+ distance: distance(sourcePin, targetPin),
96
+ },
97
+ ]
98
+ })
99
+ .sort((a, b) => a.distance - b.distance)
100
+ .slice(0, NEAREST_NEIGHBOR_COUNT)
101
+
102
+ for (const neighbor of neighbors) {
103
+ const pair: [
104
+ InputPin & { chipId: string },
105
+ InputPin & { chipId: string },
106
+ ] = [sourcePin, neighbor.pin]
107
+ const pairKey = pair
108
+ .map((p) => p.pinId)
109
+ .sort()
110
+ .join("--")
111
+
112
+ if (!addedPairKeys.has(pairKey)) {
113
+ candidatePairs.push(pair)
114
+ addedPairKeys.add(pairKey)
115
+ }
116
+ }
117
+ }
118
+ }
119
+ this.queuedCandidatePairs = candidatePairs
120
+ }
121
+
122
+ override getConstructorParams() {
123
+ return this.params
124
+ }
125
+
126
+ override _step() {
127
+ // 1. Check if a sub-solver has finished and process its result
128
+ if (this.subSolver?.solved) {
129
+ const newTracePath = this.subSolver.solvedTracePath
130
+ if (newTracePath && this.currentCandidatePair) {
131
+ const isTraceClear = !doesTraceOverlapWithExistingTraces(
132
+ newTracePath,
133
+ this.allSolvedTraces,
134
+ )
135
+
136
+ if (isTraceClear) {
137
+ const [p1, p2] = this.currentCandidatePair
138
+ const globalConnNetId = this.netConnMap.getNetConnectedToId(p1.pinId)!
139
+ const mspPairId = `${p1.pinId}-${p2.pinId}`
140
+
141
+ const newSolvedTrace: SolvedTracePath = {
142
+ mspPairId,
143
+ dcConnNetId: globalConnNetId,
144
+ globalConnNetId,
145
+ pins: [p1, p2],
146
+ tracePath: newTracePath,
147
+ mspConnectionPairIds: [mspPairId],
148
+ pinIds: [p1.pinId, p2.pinId],
149
+ }
150
+
151
+ this.solvedLongDistanceTraces.push(newSolvedTrace)
152
+ this.allSolvedTraces.push(newSolvedTrace)
153
+
154
+ this.newlyConnectedPinIds.add(p1.pinId)
155
+ this.newlyConnectedPinIds.add(p2.pinId)
156
+ }
157
+ }
158
+ this.subSolver = null
159
+ this.currentCandidatePair = null
160
+ } else if (this.subSolver?.failed) {
161
+ this.subSolver = null
162
+ this.currentCandidatePair = null
163
+ }
164
+
165
+ // 2. If a sub-solver is already running, let it continue
166
+ if (this.subSolver) {
167
+ this.subSolver.step()
168
+ return
169
+ }
170
+
171
+ // 3. Find the next valid candidate pair and start a new sub-solver
172
+ while (this.queuedCandidatePairs.length > 0) {
173
+ const nextPair = this.queuedCandidatePairs.shift()!
174
+ const [p1, p2] = nextPair
175
+
176
+ if (
177
+ this.newlyConnectedPinIds.has(p1.pinId) ||
178
+ this.newlyConnectedPinIds.has(p2.pinId)
179
+ ) {
180
+ continue
181
+ }
182
+
183
+ this.currentCandidatePair = nextPair
184
+ this.subSolver = new SchematicTraceSingleLineSolver2({
185
+ inputProblem: this.params.inputProblem,
186
+ pins: this.currentCandidatePair,
187
+ chipMap: this.chipMap,
188
+ })
189
+ return
190
+ }
191
+
192
+ // 4. If we've exited the loop, there are no more valid pairs to process
193
+ this.solved = true
194
+ }
195
+
196
+ override visualize() {
197
+ if (this.subSolver) {
198
+ return this.subSolver.visualize()
199
+ }
200
+
201
+ const graphics = visualizeInputProblem(this.inputProblem)
202
+
203
+ // Draw solved long-distance traces
204
+ for (const trace of this.solvedLongDistanceTraces) {
205
+ graphics.lines!.push({
206
+ points: trace.tracePath,
207
+ strokeColor: "purple",
208
+ })
209
+ }
210
+
211
+ // Draw queued candidate pairs
212
+ for (const [p1, p2] of this.queuedCandidatePairs) {
213
+ graphics.lines!.push({
214
+ points: [p1, p2],
215
+ strokeColor: "gray",
216
+ strokeDash: "4 4",
217
+ })
218
+ }
219
+
220
+ return graphics
221
+ }
222
+
223
+ public getOutput(): {
224
+ newTraces: SolvedTracePath[]
225
+ allTracesMerged: SolvedTracePath[]
226
+ } {
227
+ if (!this.solved) {
228
+ return { newTraces: [], allTracesMerged: this.params.alreadySolvedTraces }
229
+ }
230
+ return {
231
+ newTraces: this.solvedLongDistanceTraces,
232
+ allTracesMerged: [
233
+ ...this.params.alreadySolvedTraces,
234
+ ...this.solvedLongDistanceTraces,
235
+ ],
236
+ }
237
+ }
238
+ }
@@ -7,15 +7,19 @@ import type { GraphicsObject } from "graphics-debug"
7
7
  import { BaseSolver } from "lib/solvers/BaseSolver/BaseSolver"
8
8
  import type { InputProblem } from "lib/types/InputProblem"
9
9
  import { MspConnectionPairSolver } from "../MspConnectionPairSolver/MspConnectionPairSolver"
10
- import { SchematicTraceLinesSolver } from "../SchematicTraceLinesSolver/SchematicTraceLinesSolver"
10
+ import {
11
+ SchematicTraceLinesSolver,
12
+ type SolvedTracePath,
13
+ } from "../SchematicTraceLinesSolver/SchematicTraceLinesSolver"
11
14
  import { TraceOverlapShiftSolver } from "../TraceOverlapShiftSolver/TraceOverlapShiftSolver"
12
15
  import { NetLabelPlacementSolver } from "../NetLabelPlacementSolver/NetLabelPlacementSolver"
13
16
  import { visualizeInputProblem } from "./visualizeInputProblem"
14
- import { GuidelinesSolver } from "../GuidelinesSolver/GuidelinesSolver"
15
17
  import { TraceLabelOverlapAvoidanceSolver } from "../TraceLabelOverlapAvoidanceSolver/TraceLabelOverlapAvoidanceSolver"
16
- import { getInputChipBounds } from "../GuidelinesSolver/getInputChipBounds"
17
18
  import { correctPinsInsideChips } from "./correctPinsInsideChip"
18
19
  import { expandChipsToFitPins } from "./expandChipsToFitPins"
20
+ import { LongDistancePairSolver } from "../LongDistancePairSolver/LongDistancePairSolver"
21
+ import { MergedNetLabelObstacleSolver } from "../TraceLabelOverlapAvoidanceSolver/sub-solvers/LabelMergingSolver/LabelMergingSolver"
22
+ import { TraceCleanupSolver } from "../TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver/TraceCleanupSolver"
19
23
 
20
24
  type PipelineStep<T extends new (...args: any[]) => BaseSolver> = {
21
25
  solverName: string
@@ -24,6 +28,7 @@ type PipelineStep<T extends new (...args: any[]) => BaseSolver> = {
24
28
  instance: SchematicTracePipelineSolver,
25
29
  ) => ConstructorParameters<T>
26
30
  onSolved?: (instance: SchematicTracePipelineSolver) => void
31
+ shouldSkip?: (instance: SchematicTracePipelineSolver) => boolean
27
32
  }
28
33
 
29
34
  function definePipelineStep<
@@ -37,6 +42,7 @@ function definePipelineStep<
37
42
  getConstructorParams: (instance: SchematicTracePipelineSolver) => P,
38
43
  opts: {
39
44
  onSolved?: (instance: SchematicTracePipelineSolver) => void
45
+ shouldSkip?: (instance: SchematicTracePipelineSolver) => boolean
40
46
  } = {},
41
47
  ): PipelineStep<T> {
42
48
  return {
@@ -44,16 +50,25 @@ function definePipelineStep<
44
50
  solverClass,
45
51
  getConstructorParams,
46
52
  onSolved: opts.onSolved,
53
+ shouldSkip: opts.shouldSkip,
47
54
  }
48
55
  }
49
56
 
57
+ export interface SchematicTracePipelineSolverParams {
58
+ inputProblem: InputProblem
59
+ allowLongDistanceTraces?: boolean
60
+ }
61
+
50
62
  export class SchematicTracePipelineSolver extends BaseSolver {
51
63
  mspConnectionPairSolver?: MspConnectionPairSolver
52
64
  // guidelinesSolver?: GuidelinesSolver
53
65
  schematicTraceLinesSolver?: SchematicTraceLinesSolver
66
+ longDistancePairSolver?: LongDistancePairSolver
54
67
  traceOverlapShiftSolver?: TraceOverlapShiftSolver
55
68
  netLabelPlacementSolver?: NetLabelPlacementSolver
69
+ labelMergingSolver?: MergedNetLabelObstacleSolver
56
70
  traceLabelOverlapAvoidanceSolver?: TraceLabelOverlapAvoidanceSolver
71
+ traceCleanupSolver?: TraceCleanupSolver
57
72
 
58
73
  startTimeOfPhase: Record<string, number>
59
74
  endTimeOfPhase: Record<string, number>
@@ -96,6 +111,19 @@ export class SchematicTracePipelineSolver extends BaseSolver {
96
111
  chipMap: this.mspConnectionPairSolver!.chipMap,
97
112
  },
98
113
  ],
114
+ ),
115
+ definePipelineStep(
116
+ "longDistancePairSolver",
117
+ LongDistancePairSolver,
118
+ (instance) => [
119
+ {
120
+ inputProblem: instance.inputProblem,
121
+ primaryMspConnectionPairs:
122
+ instance.mspConnectionPairSolver!.mspConnectionPairs,
123
+ alreadySolvedTraces:
124
+ instance.schematicTraceLinesSolver!.solvedTracePaths,
125
+ },
126
+ ],
99
127
  {
100
128
  onSolved: (schematicTraceLinesSolver) => {},
101
129
  },
@@ -106,7 +134,8 @@ export class SchematicTracePipelineSolver extends BaseSolver {
106
134
  () => [
107
135
  {
108
136
  inputProblem: this.inputProblem,
109
- inputTracePaths: this.schematicTraceLinesSolver!.solvedTracePaths,
137
+ inputTracePaths:
138
+ this.longDistancePairSolver?.getOutput().allTracesMerged!,
110
139
  globalConnMap: this.mspConnectionPairSolver!.globalConnMap,
111
140
  },
112
141
  ],
@@ -123,10 +152,9 @@ export class SchematicTracePipelineSolver extends BaseSolver {
123
152
  inputTraceMap:
124
153
  this.traceOverlapShiftSolver?.correctedTraceMap ??
125
154
  Object.fromEntries(
126
- this.schematicTraceLinesSolver!.solvedTracePaths.map((p) => [
127
- p.mspPairId,
128
- p,
129
- ]),
155
+ this.longDistancePairSolver!.getOutput().allTracesMerged.map(
156
+ (p) => [p.mspPairId, p],
157
+ ),
130
158
  ),
131
159
  },
132
160
  ],
@@ -143,10 +171,9 @@ export class SchematicTracePipelineSolver extends BaseSolver {
143
171
  const traceMap =
144
172
  instance.traceOverlapShiftSolver?.correctedTraceMap ??
145
173
  Object.fromEntries(
146
- instance.schematicTraceLinesSolver!.solvedTracePaths.map((p) => [
147
- p.mspPairId,
148
- p,
149
- ]),
174
+ instance
175
+ .longDistancePairSolver!.getOutput()
176
+ .allTracesMerged.map((p) => [p.mspPairId, p]),
150
177
  )
151
178
  const traces = Object.values(traceMap)
152
179
  const netLabelPlacements =
@@ -160,18 +187,23 @@ export class SchematicTracePipelineSolver extends BaseSolver {
160
187
  },
161
188
  ]
162
189
  },
163
- {
164
- onSolved: (instance) => {
165
- if (
166
- instance.traceLabelOverlapAvoidanceSolver &&
167
- instance.netLabelPlacementSolver
168
- ) {
169
- const { netLabelPlacements } =
170
- instance.traceLabelOverlapAvoidanceSolver.getOutput()
171
- instance.netLabelPlacementSolver.netLabelPlacements =
172
- netLabelPlacements
173
- }
174
- },
190
+ ),
191
+ definePipelineStep(
192
+ "netLabelPlacementSolver",
193
+ NetLabelPlacementSolver,
194
+ (instance) => {
195
+ const traces =
196
+ instance.traceCleanupSolver?.getOutput().traces ??
197
+ instance.traceLabelOverlapAvoidanceSolver!.getOutput().traces
198
+
199
+ return [
200
+ {
201
+ inputProblem: instance.inputProblem,
202
+ inputTraceMap: Object.fromEntries(
203
+ traces.map((trace: SolvedTracePath) => [trace.mspPairId, trace]),
204
+ ),
205
+ },
206
+ ]
175
207
  },
176
208
  ),
177
209
  ]
@@ -281,16 +313,19 @@ export class SchematicTracePipelineSolver extends BaseSolver {
281
313
  }) as GraphicsObject[]),
282
314
  ]
283
315
 
284
- if (visualizations.length === 1) return visualizations[0]!
316
+ if (visualizations.length === 1) {
317
+ return visualizations[0]!
318
+ }
285
319
 
286
320
  // Simple combination of visualizations
287
- return {
321
+ const finalGraphics = {
288
322
  points: visualizations.flatMap((v) => v.points || []),
289
323
  rects: visualizations.flatMap((v) => v.rects || []),
290
324
  lines: visualizations.flatMap((v) => v.lines || []),
291
325
  circles: visualizations.flatMap((v) => v.circles || []),
292
326
  texts: visualizations.flatMap((v) => v.texts || []),
293
327
  }
328
+ return finalGraphics
294
329
  }
295
330
 
296
331
  /**