@tscircuit/schematic-trace-solver 0.0.41 → 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 (46) hide show
  1. package/dist/index.d.ts +118 -7
  2. package/dist/index.js +760 -432
  3. package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +30 -17
  4. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/TraceLabelOverlapAvoidanceSolver.ts +94 -192
  5. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/rerouteCollidingTrace.ts +13 -24
  6. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/LabelMergingSolver/LabelMergingSolver.ts +205 -0
  7. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/OverlapAvoidanceStepSolver/OverlapAvoidanceStepSolver.ts +144 -0
  8. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/SingleOverlapSolver/SingleOverlapSolver.ts +117 -0
  9. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver/TraceCleanupSolver.ts +132 -0
  10. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{balanceLShapes.ts → sub-solvers/TraceCleanupSolver/balanceLShapes.ts} +12 -10
  11. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{hasCollisions.ts → sub-solvers/TraceCleanupSolver/hasCollisions.ts} +1 -1
  12. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{hasCollisionsWithLabels.ts → sub-solvers/TraceCleanupSolver/hasCollisionsWithLabels.ts} +1 -1
  13. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{minimizeTurnsWithFilteredLabels.ts → sub-solvers/TraceCleanupSolver/minimizeTurnsWithFilteredLabels.ts} +6 -6
  14. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{simplifyPath.ts → sub-solvers/TraceCleanupSolver/simplifyPath.ts} +1 -1
  15. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{turnMinimization.ts → sub-solvers/TraceCleanupSolver/turnMinimization.ts} +0 -2
  16. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/tryFourPointDetour.ts +104 -0
  17. package/lib/solvers/TraceLabelOverlapAvoidanceSolver/trySnipAndReconnect.ts +24 -154
  18. package/package.json +1 -1
  19. package/tests/assets/1.input.json +379 -0
  20. package/tests/assets/2.input.json +330 -0
  21. package/tests/assets/3.input.json +388 -0
  22. package/tests/assets/MergedNetLabelObstacles.test.input.json +154 -0
  23. package/tests/assets/OverlapAvoidanceStepSolver.test.input.json +682 -0
  24. package/tests/assets/SingleOverlapSolver.test.input.json +170 -0
  25. package/tests/assets/TraceCleanupSolver.test.input.json +216 -0
  26. package/tests/assets/TraceLabelOverlapAvoidanceSolver.test.input.json +424 -0
  27. package/tests/examples/__snapshots__/example25.snap.svg +3 -3
  28. package/tests/examples/__snapshots__/example26.snap.svg +3 -3
  29. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/TraceLabelOverlapAvoidanceSolver.test.ts +18 -0
  30. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/__snapshots__/TraceLabelOverlapAvoidanceSolver.snap.svg +243 -0
  31. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/__snapshots__/renderComparisonView01.snap.svg +223 -0
  32. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/__snapshots__/renderComparisonView02.snap.svg +205 -0
  33. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/__snapshots__/renderComparisonView03.snap.svg +184 -0
  34. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/renderComparisonView01.test.ts +29 -0
  35. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/renderComparisonView02.test.ts +27 -0
  36. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/renderComparisonView03.test.ts +39 -0
  37. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/MergedNetLabelObstacles.test.ts +14 -0
  38. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/OverlapAvoidanceStepSolver.test.ts +20 -0
  39. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/SingleOverlapSolver.test.ts +10 -0
  40. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/TraceCleanupSolver.test.ts +19 -0
  41. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/MergedNetLabelObstacles.snap.svg +140 -0
  42. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/OverlapAvoidanceStepSolver.snap.svg +216 -0
  43. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/SingleOverlapSolver.snap.svg +125 -0
  44. package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/TraceCleanupSolver.snap.svg +119 -0
  45. /package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{countTurns.ts → sub-solvers/TraceCleanupSolver/countTurns.ts} +0 -0
  46. /package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{tryConnectPoints.ts → sub-solvers/TraceCleanupSolver/tryConnectPoints.ts} +0 -0
@@ -7,16 +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"
19
20
  import { LongDistancePairSolver } from "../LongDistancePairSolver/LongDistancePairSolver"
21
+ import { MergedNetLabelObstacleSolver } from "../TraceLabelOverlapAvoidanceSolver/sub-solvers/LabelMergingSolver/LabelMergingSolver"
22
+ import { TraceCleanupSolver } from "../TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver/TraceCleanupSolver"
20
23
 
21
24
  type PipelineStep<T extends new (...args: any[]) => BaseSolver> = {
22
25
  solverName: string
@@ -63,7 +66,9 @@ export class SchematicTracePipelineSolver extends BaseSolver {
63
66
  longDistancePairSolver?: LongDistancePairSolver
64
67
  traceOverlapShiftSolver?: TraceOverlapShiftSolver
65
68
  netLabelPlacementSolver?: NetLabelPlacementSolver
69
+ labelMergingSolver?: MergedNetLabelObstacleSolver
66
70
  traceLabelOverlapAvoidanceSolver?: TraceLabelOverlapAvoidanceSolver
71
+ traceCleanupSolver?: TraceCleanupSolver
67
72
 
68
73
  startTimeOfPhase: Record<string, number>
69
74
  endTimeOfPhase: Record<string, number>
@@ -182,18 +187,23 @@ export class SchematicTracePipelineSolver extends BaseSolver {
182
187
  },
183
188
  ]
184
189
  },
185
- {
186
- onSolved: (instance) => {
187
- if (
188
- instance.traceLabelOverlapAvoidanceSolver &&
189
- instance.netLabelPlacementSolver
190
- ) {
191
- const { netLabelPlacements } =
192
- instance.traceLabelOverlapAvoidanceSolver.getOutput()
193
- instance.netLabelPlacementSolver.netLabelPlacements =
194
- netLabelPlacements
195
- }
196
- },
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
+ ]
197
207
  },
198
208
  ),
199
209
  ]
@@ -303,16 +313,19 @@ export class SchematicTracePipelineSolver extends BaseSolver {
303
313
  }) as GraphicsObject[]),
304
314
  ]
305
315
 
306
- if (visualizations.length === 1) return visualizations[0]!
316
+ if (visualizations.length === 1) {
317
+ return visualizations[0]!
318
+ }
307
319
 
308
320
  // Simple combination of visualizations
309
- return {
321
+ const finalGraphics = {
310
322
  points: visualizations.flatMap((v) => v.points || []),
311
323
  rects: visualizations.flatMap((v) => v.rects || []),
312
324
  lines: visualizations.flatMap((v) => v.lines || []),
313
325
  circles: visualizations.flatMap((v) => v.circles || []),
314
326
  texts: visualizations.flatMap((v) => v.texts || []),
315
327
  }
328
+ return finalGraphics
316
329
  }
317
330
 
318
331
  /**
@@ -1,16 +1,13 @@
1
1
  import { BaseSolver } from "../BaseSolver/BaseSolver"
2
- import { detectTraceLabelOverlap } from "./detectTraceLabelOverlap"
3
- import { rerouteCollidingTrace } from "./rerouteCollidingTrace"
4
2
  import type { SolvedTracePath } from "../SchematicTraceLinesSolver/SchematicTraceLinesSolver"
5
3
  import type { NetLabelPlacement } from "../NetLabelPlacementSolver/NetLabelPlacementSolver"
6
4
  import type { GraphicsObject } from "graphics-debug"
7
5
  import { visualizeInputProblem } from "../SchematicTracePipelineSolver/visualizeInputProblem"
8
- import { getRectBounds } from "../NetLabelPlacementSolver/SingleNetLabelPlacementSolver/geometry"
6
+ import type { InputProblem } from "../../types/InputProblem"
7
+ import { MergedNetLabelObstacleSolver } from "./sub-solvers/LabelMergingSolver/LabelMergingSolver"
8
+ import { TraceCleanupSolver } from "./sub-solvers/TraceCleanupSolver/TraceCleanupSolver"
9
9
  import { getColorFromString } from "lib/utils/getColorFromString"
10
- import type { InputProblem } from "lib/types/InputProblem"
11
- import { minimizeTurnsWithFilteredLabels } from "./minimizeTurnsWithFilteredLabels"
12
- import { balanceLShapes } from "./balanceLShapes"
13
- import { NetLabelPlacementSolver } from "../NetLabelPlacementSolver/NetLabelPlacementSolver"
10
+ import { OverlapAvoidanceStepSolver } from "./sub-solvers/OverlapAvoidanceStepSolver/OverlapAvoidanceStepSolver"
14
11
 
15
12
  interface TraceLabelOverlapAvoidanceSolverInput {
16
13
  inputProblem: InputProblem
@@ -18,222 +15,127 @@ interface TraceLabelOverlapAvoidanceSolverInput {
18
15
  netLabelPlacements: NetLabelPlacement[]
19
16
  }
20
17
 
18
+ /**
19
+ * This solver is a pipeline that runs a series of sub-solvers to resolve
20
+ * trace-label overlaps and clean up the resulting traces.
21
+ */
21
22
  export class TraceLabelOverlapAvoidanceSolver extends BaseSolver {
22
- private problem: InputProblem
23
- private traces: SolvedTracePath[]
24
- private netTempLabelPlacements: NetLabelPlacement[]
25
- private netLabelPlacements: NetLabelPlacement[]
26
- private updatedTraces: SolvedTracePath[]
27
- private mergedLabelNetIdMap: Record<string, Set<string>>
28
- private detourCountByLabel: Record<string, number>
29
- private readonly PADDING_BUFFER = 0.1
23
+ inputProblem: InputProblem
24
+ traces: SolvedTracePath[]
25
+ netLabelPlacements: NetLabelPlacement[]
26
+
27
+ // sub-solver instances
28
+ labelMergingSolver?: MergedNetLabelObstacleSolver
29
+ overlapAvoidanceSolver?: OverlapAvoidanceStepSolver
30
+ traceCleanupSolver?: TraceCleanupSolver
31
+ pipelineStepIndex = 0
30
32
 
31
33
  constructor(solverInput: TraceLabelOverlapAvoidanceSolverInput) {
32
34
  super()
33
- this.problem = solverInput.inputProblem
35
+ this.inputProblem = solverInput.inputProblem
34
36
  this.traces = solverInput.traces
35
- this.updatedTraces = [...solverInput.traces]
36
- this.mergedLabelNetIdMap = {}
37
- this.detourCountByLabel = {}
38
-
39
- const originalLabels = solverInput.netLabelPlacements
40
- this.netLabelPlacements = originalLabels
41
- if (!originalLabels || originalLabels.length === 0) {
42
- this.netTempLabelPlacements = []
43
- return
44
- }
45
-
46
- const labelGroups: Record<string, NetLabelPlacement[]> = {}
47
-
48
- for (const p of originalLabels) {
49
- if (p.pinIds.length === 0) continue
50
- const chipId = p.pinIds[0].split(".")[0]
51
- if (!chipId) continue
52
- const key = `${chipId}-${p.orientation}`
53
- if (!(key in labelGroups)) {
54
- labelGroups[key] = []
55
- }
56
- labelGroups[key]!.push(p)
57
- }
58
-
59
- const finalPlacements: NetLabelPlacement[] = []
60
- for (const [key, group] of Object.entries(labelGroups)) {
61
- if (group.length <= 1) {
62
- finalPlacements.push(...group)
63
- continue
64
- }
65
-
66
- let minX = Infinity,
67
- minY = Infinity,
68
- maxX = -Infinity,
69
- maxY = -Infinity
70
- for (const p of group) {
71
- const bounds = getRectBounds(p.center, p.width, p.height)
72
- minX = Math.min(minX, bounds.minX)
73
- minY = Math.min(minY, bounds.minY)
74
- maxX = Math.max(maxX, bounds.maxX)
75
- maxY = Math.max(maxY, bounds.maxY)
76
- }
77
-
78
- const newWidth = maxX - minX
79
- const newHeight = maxY - minY
80
- const template = group[0]!
81
- const syntheticId = `merged-group-${key}`
82
- const originalNetIds = new Set(group.map((p) => p.globalConnNetId))
83
- this.mergedLabelNetIdMap[syntheticId] = originalNetIds
84
-
85
- finalPlacements.push({
86
- ...template,
87
- globalConnNetId: syntheticId,
88
- width: newWidth,
89
- height: newHeight,
90
- center: { x: minX + newWidth / 2, y: minY + newHeight / 2 },
91
- pinIds: [...new Set(group.flatMap((p) => p.pinIds))],
92
- mspConnectionPairIds: [
93
- ...new Set(group.flatMap((p) => p.mspConnectionPairIds)),
94
- ],
95
- })
96
- }
97
-
98
- this.netTempLabelPlacements = finalPlacements
37
+ this.netLabelPlacements = solverInput.netLabelPlacements
99
38
  }
100
39
 
101
40
  override _step() {
102
- if (
103
- !this.traces ||
104
- this.traces.length === 0 ||
105
- !this.netTempLabelPlacements ||
106
- this.netTempLabelPlacements.length === 0
107
- ) {
108
- this.solved = true
109
- return
110
- }
111
-
112
- this.detourCountByLabel = {}
113
-
114
- const overlaps = detectTraceLabelOverlap(
115
- this.traces,
116
- this.netTempLabelPlacements,
117
- )
118
-
119
- if (overlaps.length === 0) {
120
- this.solved = true
121
- return
122
- }
123
-
124
- const unfriendlyOverlaps = overlaps.filter((o) => {
125
- const originalNetIds = this.mergedLabelNetIdMap[o.label.globalConnNetId]
126
- if (originalNetIds) {
127
- return !originalNetIds.has(o.trace.globalConnNetId)
41
+ // If a sub-solver is active, step it and check for completion.
42
+ if (this.activeSubSolver) {
43
+ this.activeSubSolver.step()
44
+
45
+ if (this.activeSubSolver.solved) {
46
+ this.activeSubSolver = null
47
+ this.pipelineStepIndex++
48
+ } else if (this.activeSubSolver.failed) {
49
+ this.failed = true // If any sub-solver fails, the whole thing fails
50
+ this.activeSubSolver = null
128
51
  }
129
- return o.trace.globalConnNetId !== o.label.globalConnNetId
130
- })
131
-
132
- if (unfriendlyOverlaps.length === 0) {
133
- this.solved = true
134
- return
52
+ return // Return to allow the sub-solver to run
135
53
  }
136
54
 
137
- const updatedTracesMap: Record<string, SolvedTracePath> = {}
138
- for (const trace of this.traces) {
139
- updatedTracesMap[trace.mspPairId] = trace
55
+ // If no sub-solver is active, create the next one in the pipeline.
56
+ switch (this.pipelineStepIndex) {
57
+ case 0:
58
+ this.labelMergingSolver = new MergedNetLabelObstacleSolver({
59
+ netLabelPlacements: this.netLabelPlacements,
60
+ inputProblem: this.inputProblem,
61
+ traces: this.traces,
62
+ })
63
+ this.activeSubSolver = this.labelMergingSolver
64
+ break
65
+
66
+ case 1:
67
+ this.overlapAvoidanceSolver = new OverlapAvoidanceStepSolver({
68
+ inputProblem: this.inputProblem,
69
+ traces: this.traces,
70
+ netLabelPlacements:
71
+ this.labelMergingSolver!.getOutput().netLabelPlacements,
72
+ mergedLabelNetIdMap:
73
+ this.labelMergingSolver!.getOutput().mergedLabelNetIdMap,
74
+ })
75
+ this.activeSubSolver = this.overlapAvoidanceSolver
76
+ break
77
+
78
+ case 2:
79
+ this.traceCleanupSolver = new TraceCleanupSolver({
80
+ inputProblem: this.inputProblem,
81
+ allTraces: this.overlapAvoidanceSolver!.getOutput().allTraces,
82
+ targetTraceIds: new Set(
83
+ this.overlapAvoidanceSolver!.getOutput().modifiedTraces.map(
84
+ (t) => t.mspPairId,
85
+ ),
86
+ ),
87
+ allLabelPlacements:
88
+ this.labelMergingSolver!.getOutput().netLabelPlacements,
89
+ mergedLabelNetIdMap:
90
+ this.labelMergingSolver!.getOutput().mergedLabelNetIdMap,
91
+ paddingBuffer: 0.01,
92
+ })
93
+ this.activeSubSolver = this.traceCleanupSolver
94
+ break
95
+
96
+ default:
97
+ this.solved = true
98
+ break
140
99
  }
141
-
142
- const processedTraceIds = new Set<string>()
143
-
144
- for (const overlap of unfriendlyOverlaps) {
145
- if (processedTraceIds.has(overlap.trace.mspPairId)) {
146
- continue
147
- }
148
-
149
- const currentTraceState = updatedTracesMap[overlap.trace.mspPairId]!
150
- const labelId = overlap.label.globalConnNetId
151
- const detourCount = this.detourCountByLabel[labelId] || 0
152
-
153
- const newTrace = rerouteCollidingTrace({
154
- trace: currentTraceState,
155
- label: overlap.label,
156
- problem: this.problem,
157
- paddingBuffer: this.PADDING_BUFFER,
158
- detourCount,
159
- })
160
-
161
- if (newTrace.tracePath !== currentTraceState.tracePath) {
162
- this.detourCountByLabel[labelId] = detourCount + 1
163
- }
164
-
165
- updatedTracesMap[currentTraceState.mspPairId] = newTrace
166
- processedTraceIds.add(currentTraceState.mspPairId)
167
- }
168
-
169
- this.updatedTraces = Object.values(updatedTracesMap)
170
-
171
- const minimizedTraces = minimizeTurnsWithFilteredLabels({
172
- traces: this.updatedTraces,
173
- problem: this.problem,
174
- allLabelPlacements: this.netTempLabelPlacements, // Use temp labels which include merged ones
175
- mergedLabelNetIdMap: this.mergedLabelNetIdMap,
176
- paddingBuffer: this.PADDING_BUFFER,
177
- })
178
- if (minimizedTraces) {
179
- this.updatedTraces = minimizedTraces
180
- }
181
- const balancedTraces = balanceLShapes({
182
- traces: this.updatedTraces,
183
- problem: this.problem,
184
- allLabelPlacements: this.netLabelPlacements,
185
- })
186
- if (balancedTraces) {
187
- this.updatedTraces = balancedTraces
188
- }
189
-
190
- const finalLabelPlacementSolver = new NetLabelPlacementSolver({
191
- inputProblem: this.problem,
192
- inputTraceMap: Object.fromEntries(
193
- this.updatedTraces.map((trace) => [trace.mspPairId, trace]),
194
- ),
195
- })
196
- finalLabelPlacementSolver.solve()
197
- if (!finalLabelPlacementSolver.failed) {
198
- this.netLabelPlacements = finalLabelPlacementSolver.netLabelPlacements
199
- }
200
-
201
- this.solved = true
202
100
  }
203
101
 
204
102
  getOutput() {
205
103
  return {
206
- traces: this.updatedTraces,
207
- netLabelPlacements: this.netLabelPlacements,
104
+ traces: this.traceCleanupSolver?.getOutput().traces ?? this.traces,
105
+ netLabelPlacements:
106
+ this.labelMergingSolver?.getOutput().netLabelPlacements ??
107
+ this.netLabelPlacements,
208
108
  }
209
109
  }
210
110
 
211
111
  override visualize(): GraphicsObject {
212
- const graphics = visualizeInputProblem(this.problem)
112
+ if (this.activeSubSolver) {
113
+ return this.activeSubSolver.visualize()
114
+ }
213
115
 
116
+ // When no sub-solver is active, show the current state of the pipeline
117
+ const graphics = visualizeInputProblem(this.inputProblem)
214
118
  if (!graphics.lines) graphics.lines = []
215
- if (!graphics.circles) graphics.circles = []
216
- if (!graphics.texts) graphics.texts = []
217
119
  if (!graphics.rects) graphics.rects = []
218
120
 
219
- for (const trace of this.updatedTraces) {
121
+ const output = this.getOutput()
122
+
123
+ for (const trace of output.traces) {
220
124
  graphics.lines!.push({
221
125
  points: trace.tracePath,
222
126
  strokeColor: "purple",
223
127
  })
224
128
  }
225
129
 
226
- for (const p of this.netLabelPlacements) {
130
+ for (const label of output.netLabelPlacements) {
131
+ const color = getColorFromString(label.globalConnNetId, 0.3)
227
132
  graphics.rects!.push({
228
- center: p.center,
229
- width: p.width,
230
- height: p.height,
231
- fill: getColorFromString(p.globalConnNetId, 0.35),
232
- })
233
- graphics.points!.push({
234
- x: p.anchorPoint.x,
235
- y: p.anchorPoint.y,
236
- color: getColorFromString(p.globalConnNetId, 0.9),
133
+ center: label.center,
134
+ width: label.width,
135
+ height: label.height,
136
+ fill: color,
137
+ stroke: color.replace("0.3", "1"),
138
+ label: label.globalConnNetId,
237
139
  })
238
140
  }
239
141
 
@@ -1,16 +1,16 @@
1
+ import type { Point } from "@tscircuit/math-utils"
1
2
  import type { SolvedTracePath } from "../SchematicTraceLinesSolver/SchematicTraceLinesSolver"
2
3
  import type { NetLabelPlacement } from "../NetLabelPlacementSolver/NetLabelPlacementSolver"
3
4
  import { getRectBounds } from "../NetLabelPlacementSolver/SingleNetLabelPlacementSolver/geometry"
4
- import { getObstacleRects } from "../SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/rect"
5
5
  import type { InputProblem } from "lib/types/InputProblem"
6
6
  import { findTraceViolationZone } from "./violation"
7
- import { tryFourPointDetour, trySnipAndReconnect } from "./trySnipAndReconnect"
8
- import { simplifyPath } from "./simplifyPath"
7
+ import { generateSnipAndReconnectCandidates } from "./trySnipAndReconnect"
8
+ import { simplifyPath } from "./sub-solvers/TraceCleanupSolver/simplifyPath"
9
+ import { generateFourPointDetourCandidates } from "./tryFourPointDetour"
9
10
 
10
- export const rerouteCollidingTrace = ({
11
+ export const generateRerouteCandidates = ({
11
12
  trace,
12
13
  label,
13
- problem,
14
14
  paddingBuffer,
15
15
  detourCount,
16
16
  }: {
@@ -19,14 +19,13 @@ export const rerouteCollidingTrace = ({
19
19
  problem: InputProblem
20
20
  paddingBuffer: number
21
21
  detourCount: number
22
- }): SolvedTracePath => {
22
+ }): Point[][] => {
23
23
  const initialTrace = { ...trace, tracePath: simplifyPath(trace.tracePath) }
24
24
 
25
25
  if (trace.globalConnNetId === label.globalConnNetId) {
26
- return initialTrace
26
+ return [initialTrace.tracePath]
27
27
  }
28
28
 
29
- const obstacles = getObstacleRects(problem)
30
29
  const labelPadding = paddingBuffer
31
30
  const labelBoundsRaw = getRectBounds(label.center, label.width, label.height)
32
31
  const labelBounds = {
@@ -37,37 +36,27 @@ export const rerouteCollidingTrace = ({
37
36
  chipId: `netlabel-${label.netId}`,
38
37
  }
39
38
 
40
- const fourPointResult = tryFourPointDetour({
39
+ const fourPointCandidates = generateFourPointDetourCandidates({
41
40
  initialTrace,
42
41
  label,
43
42
  labelBounds,
44
- obstacles,
45
43
  paddingBuffer,
46
44
  detourCount,
47
45
  })
48
- if (fourPointResult) {
49
- initialTrace.tracePath = fourPointResult.tracePath
50
- }
46
+
51
47
  const { firstInsideIndex, lastInsideIndex } = findTraceViolationZone(
52
48
  initialTrace.tracePath,
53
49
  labelBounds,
54
50
  )
55
51
 
56
- const snipReconnectResult = trySnipAndReconnect({
52
+ const snipReconnectCandidates = generateSnipAndReconnectCandidates({
57
53
  initialTrace,
58
54
  firstInsideIndex,
59
55
  lastInsideIndex,
60
56
  labelBounds,
61
- obstacles,
57
+ paddingBuffer,
58
+ detourCount,
62
59
  })
63
60
 
64
- if (snipReconnectResult) {
65
- return snipReconnectResult
66
- }
67
-
68
- if (fourPointResult) {
69
- return fourPointResult
70
- }
71
-
72
- return initialTrace
61
+ return [...fourPointCandidates, ...snipReconnectCandidates]
73
62
  }