@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.
- package/dist/index.d.ts +118 -7
- package/dist/index.js +760 -432
- package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +30 -17
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/TraceLabelOverlapAvoidanceSolver.ts +94 -192
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/rerouteCollidingTrace.ts +13 -24
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/LabelMergingSolver/LabelMergingSolver.ts +205 -0
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/OverlapAvoidanceStepSolver/OverlapAvoidanceStepSolver.ts +144 -0
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/SingleOverlapSolver/SingleOverlapSolver.ts +117 -0
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/TraceCleanupSolver/TraceCleanupSolver.ts +132 -0
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{balanceLShapes.ts → sub-solvers/TraceCleanupSolver/balanceLShapes.ts} +12 -10
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{hasCollisions.ts → sub-solvers/TraceCleanupSolver/hasCollisions.ts} +1 -1
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{hasCollisionsWithLabels.ts → sub-solvers/TraceCleanupSolver/hasCollisionsWithLabels.ts} +1 -1
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{minimizeTurnsWithFilteredLabels.ts → sub-solvers/TraceCleanupSolver/minimizeTurnsWithFilteredLabels.ts} +6 -6
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{simplifyPath.ts → sub-solvers/TraceCleanupSolver/simplifyPath.ts} +1 -1
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{turnMinimization.ts → sub-solvers/TraceCleanupSolver/turnMinimization.ts} +0 -2
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/tryFourPointDetour.ts +104 -0
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/trySnipAndReconnect.ts +24 -154
- package/package.json +1 -1
- package/tests/assets/1.input.json +379 -0
- package/tests/assets/2.input.json +330 -0
- package/tests/assets/3.input.json +388 -0
- package/tests/assets/MergedNetLabelObstacles.test.input.json +154 -0
- package/tests/assets/OverlapAvoidanceStepSolver.test.input.json +682 -0
- package/tests/assets/SingleOverlapSolver.test.input.json +170 -0
- package/tests/assets/TraceCleanupSolver.test.input.json +216 -0
- package/tests/assets/TraceLabelOverlapAvoidanceSolver.test.input.json +424 -0
- package/tests/examples/__snapshots__/example25.snap.svg +3 -3
- package/tests/examples/__snapshots__/example26.snap.svg +3 -3
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/TraceLabelOverlapAvoidanceSolver.test.ts +18 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/__snapshots__/TraceLabelOverlapAvoidanceSolver.snap.svg +243 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/__snapshots__/renderComparisonView01.snap.svg +223 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/__snapshots__/renderComparisonView02.snap.svg +205 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/__snapshots__/renderComparisonView03.snap.svg +184 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/renderComparisonView01.test.ts +29 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/renderComparisonView02.test.ts +27 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/renderComparisonView/renderComparisonView03.test.ts +39 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/MergedNetLabelObstacles.test.ts +14 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/OverlapAvoidanceStepSolver.test.ts +20 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/SingleOverlapSolver.test.ts +10 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/TraceCleanupSolver.test.ts +19 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/MergedNetLabelObstacles.snap.svg +140 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/OverlapAvoidanceStepSolver.snap.svg +216 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/SingleOverlapSolver.snap.svg +125 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/sub-solver/__snapshots__/TraceCleanupSolver.snap.svg +119 -0
- /package/lib/solvers/TraceLabelOverlapAvoidanceSolver/{countTurns.ts → sub-solvers/TraceCleanupSolver/countTurns.ts} +0 -0
- /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 {
|
|
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
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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)
|
|
316
|
+
if (visualizations.length === 1) {
|
|
317
|
+
return visualizations[0]!
|
|
318
|
+
}
|
|
307
319
|
|
|
308
320
|
// Simple combination of visualizations
|
|
309
|
-
|
|
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 {
|
|
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
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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.
|
|
35
|
+
this.inputProblem = solverInput.inputProblem
|
|
34
36
|
this.traces = solverInput.traces
|
|
35
|
-
this.
|
|
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
|
-
|
|
103
|
-
|
|
104
|
-
this.
|
|
105
|
-
|
|
106
|
-
this.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
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
|
|
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
|
-
|
|
138
|
-
|
|
139
|
-
|
|
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.
|
|
207
|
-
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
|
-
|
|
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
|
-
|
|
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
|
|
130
|
+
for (const label of output.netLabelPlacements) {
|
|
131
|
+
const color = getColorFromString(label.globalConnNetId, 0.3)
|
|
227
132
|
graphics.rects!.push({
|
|
228
|
-
center:
|
|
229
|
-
width:
|
|
230
|
-
height:
|
|
231
|
-
fill:
|
|
232
|
-
|
|
233
|
-
|
|
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 {
|
|
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
|
|
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
|
-
}):
|
|
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
|
|
39
|
+
const fourPointCandidates = generateFourPointDetourCandidates({
|
|
41
40
|
initialTrace,
|
|
42
41
|
label,
|
|
43
42
|
labelBounds,
|
|
44
|
-
obstacles,
|
|
45
43
|
paddingBuffer,
|
|
46
44
|
detourCount,
|
|
47
45
|
})
|
|
48
|
-
|
|
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
|
|
52
|
+
const snipReconnectCandidates = generateSnipAndReconnectCandidates({
|
|
57
53
|
initialTrace,
|
|
58
54
|
firstInsideIndex,
|
|
59
55
|
lastInsideIndex,
|
|
60
56
|
labelBounds,
|
|
61
|
-
|
|
57
|
+
paddingBuffer,
|
|
58
|
+
detourCount,
|
|
62
59
|
})
|
|
63
60
|
|
|
64
|
-
|
|
65
|
-
return snipReconnectResult
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (fourPointResult) {
|
|
69
|
-
return fourPointResult
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
return initialTrace
|
|
61
|
+
return [...fourPointCandidates, ...snipReconnectCandidates]
|
|
73
62
|
}
|