@tscircuit/schematic-trace-solver 0.0.174 → 0.0.176

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 (63) hide show
  1. package/dist/index.d.ts +5 -0
  2. package/dist/index.js +759 -91
  3. package/lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts +5 -1
  4. package/lib/solvers/InlineNetLabelSolver/InlineNetLabelSolver.ts +16 -1
  5. package/lib/solvers/InlineNetLabelSolver/restoreReroutesAroundSupersededLabels.ts +174 -0
  6. package/lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts +2 -30
  7. package/lib/solvers/SameNetJunctionAlignmentSolver/SameNetJunctionAlignmentSolver.ts +2 -0
  8. package/lib/solvers/SameNetJunctionAlignmentSolver/alignSameNetJunctions.ts +748 -15
  9. package/lib/solvers/SameNetJunctionAlignmentSolver/findNearestSharedPinExitRail.ts +140 -0
  10. package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +12 -5
  11. package/lib/utils/doesPathCoincideWithTraces.ts +17 -4
  12. package/lib/utils/pathIntersectsRenderedLabel.ts +33 -0
  13. package/package.json +1 -1
  14. package/site/bug-reports/bug-report-20260901T055358Z.page.tsx +4 -0
  15. package/site/bug-reports/bug-report-20260901T064117Z.page.tsx +4 -0
  16. package/site/bug-reports/bug-report-20260901T134241Z.page.tsx +4 -0
  17. package/tests/bug-reports/bug-report-20260707T134549Z/__snapshots__/bug-report-20260707T134549Z.snap.svg +2 -2
  18. package/tests/bug-reports/bug-report-20260707T134549Z/bug-report-20260707T134549Z.test.ts +9 -0
  19. package/tests/bug-reports/bug-report-20260707T230831Z/__snapshots__/bug-report-20260707T230831Z.snap.svg +2 -2
  20. package/tests/bug-reports/bug-report-20260717T042845Z/__snapshots__/bug-report-20260717T042845Z.snap.svg +2 -2
  21. package/tests/bug-reports/bug-report-20260721T221026Z/__snapshots__/bug-report-20260721T221026Z.snap.svg +2 -2
  22. package/tests/bug-reports/bug-report-20260730T061837Z/__snapshots__/bug-report-20260730T061837Z.snap.svg +2 -2
  23. package/tests/bug-reports/bug-report-20260730T061837Z/bug-report-20260730T061837Z.test.ts +8 -4
  24. package/tests/bug-reports/bug-report-20260804T171919Z/__snapshots__/bug-report-20260804T171919Z.snap.svg +2 -2
  25. package/tests/bug-reports/bug-report-20260805T061316Z/__snapshots__/bug-report-20260805T061316Z.snap.svg +2 -2
  26. package/tests/bug-reports/bug-report-20260806T061548Z/__snapshots__/bug-report-20260806T061548Z.snap.svg +2 -2
  27. package/tests/bug-reports/bug-report-20260825T045913Z/__snapshots__/bug-report-20260825T045913Z.snap.svg +2 -2
  28. package/tests/bug-reports/bug-report-20260826T072956Z/__snapshots__/bug-report-20260826T072956Z.snap.svg +6 -6
  29. package/tests/bug-reports/bug-report-20260901T055358Z/__snapshots__/bug-report-20260901T055358Z.snap.svg +676 -0
  30. package/tests/bug-reports/bug-report-20260901T055358Z/bug-report-20260901T055358Z.json +2467 -0
  31. package/tests/bug-reports/bug-report-20260901T055358Z/bug-report-20260901T055358Z.test.ts +59 -0
  32. package/tests/bug-reports/bug-report-20260901T064117Z/__snapshots__/bug-report-20260901T064117Z.snap.svg +134 -0
  33. package/tests/bug-reports/bug-report-20260901T064117Z/bug-report-20260901T064117Z.json +215 -0
  34. package/tests/bug-reports/bug-report-20260901T064117Z/bug-report-20260901T064117Z.test.ts +12 -0
  35. package/tests/bug-reports/bug-report-20260901T134241Z/__snapshots__/bug-report-20260901T134241Z.snap.svg +115 -0
  36. package/tests/bug-reports/bug-report-20260901T134241Z/bug-report-20260901T134241Z.json +359 -0
  37. package/tests/bug-reports/bug-report-20260901T134241Z/bug-report-20260901T134241Z.test.ts +60 -0
  38. package/tests/examples/__snapshots__/example51.snap.svg +2 -2
  39. package/tests/repros/__snapshots__/board-1273-trace-overlap-cycle.snap.svg +10 -10
  40. package/tests/repros/__snapshots__/board1096-usb-label-overlap-iteration.snap.svg +2 -2
  41. package/tests/repros/__snapshots__/repro-bq25895-cross-net-trace-overlap.snap.svg +2 -2
  42. package/tests/repros/__snapshots__/repro-core-ground-inline-label-fallback.snap.svg +10 -10
  43. package/tests/repros/__snapshots__/repro-example35-minimize-trace-crossing.snap.svg +2 -2
  44. package/tests/repros/__snapshots__/repro-isolated-rs485-isow7841.snap.svg +18 -18
  45. package/tests/repros/__snapshots__/repro-pga300-redundant-ground-traces.snap.svg +18 -18
  46. package/tests/repros/__snapshots__/repro-pmp11282-isolated-dcdc.snap.svg +10 -10
  47. package/tests/repros/__snapshots__/repro-powerbank-3v-system-power.snap.svg +2 -2
  48. package/tests/repros/__snapshots__/repro-ti-power-output-section.snap.svg +2 -2
  49. package/tests/repros/__snapshots__/repro-tida-01389-hbridge.snap.svg +2 -2
  50. package/tests/repros/__snapshots__/repro-tida010076-page02.snap.svg +2 -2
  51. package/tests/repros/__snapshots__/repro-trellis-core-gnd-net-label-overlap.snap.svg +134 -0
  52. package/tests/repros/__snapshots__/repro-wireless-mouse-charger-section.snap.svg +164 -0
  53. package/tests/repros/__snapshots__/repro161-power-section-autolayout.snap.svg +2 -2
  54. package/tests/repros/__snapshots__/repro48-555-timer-vcc-rail-label.snap.svg +2 -2
  55. package/tests/repros/assets/repro-trellis-core-gnd-net-label-overlap.input.json +178 -0
  56. package/tests/repros/assets/repro-wireless-mouse-charger-section.input.json +591 -0
  57. package/tests/repros/repro-isolated-rs485-isow7841.test.ts +4 -1
  58. package/tests/repros/repro-powerbank-3v-system-power.test.ts +24 -0
  59. package/tests/repros/repro-tida-01389-hbridge.test.ts +24 -0
  60. package/tests/repros/repro-trellis-core-gnd-net-label-overlap.test.ts +73 -0
  61. package/tests/repros/repro-wireless-mouse-charger-section.test.ts +16 -0
  62. package/tests/solvers/InlineNetLabelSolver/restore-reroutes-around-superseded-labels.test.ts +186 -0
  63. package/tests/solvers/SameNetJunctionAlignmentSolver/parallel-load-rails.test.ts +1 -0
@@ -9,6 +9,7 @@ import {
9
9
  getRectBounds,
10
10
  } from "lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/geometry"
11
11
  import { tracePathContainsPoint } from "lib/solvers/RailNetLabelCornerPlacementSolver/geometry"
12
+ import type { MspConnectionPairId } from "lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver"
12
13
  import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
13
14
  import type {
14
15
  ChipId,
@@ -60,6 +61,8 @@ export class AvailableNetOrientationSolver extends BaseSolver {
60
61
  inputProblem: InputProblem
61
62
  traces: SolvedTracePath[]
62
63
  netLabelPlacements: NetLabelPlacement[]
64
+ /** Exact provenance for connector traces created by this solver. */
65
+ readonly netLabelConnectorTraceIds = new Set<MspConnectionPairId>()
63
66
 
64
67
  outputNetLabelPlacements: NetLabelPlacement[]
65
68
  queuedLabelIndices: number[] = []
@@ -374,6 +377,7 @@ export class AvailableNetOrientationSolver extends BaseSolver {
374
377
 
375
378
  this.traces.push(connectorTrace)
376
379
  this.traceMap[mspPairId] = connectorTrace
380
+ this.netLabelConnectorTraceIds.add(mspPairId)
377
381
  }
378
382
 
379
383
  private finish() {
@@ -829,7 +833,7 @@ export class AvailableNetOrientationSolver extends BaseSolver {
829
833
  foundConnectedTrace = false
830
834
  for (const trace of Object.values(this.traceMap)) {
831
835
  if (connectedTraceIds.has(trace.mspPairId)) continue
832
- if (trace.mspPairId.startsWith("available-net-orientation-")) continue
836
+ if (this.netLabelConnectorTraceIds.has(trace.mspPairId)) continue
833
837
  if (trace.globalConnNetId !== label.globalConnNetId) continue
834
838
  if (!trace.pinIds.some((pinId) => connectedPinIds.has(pinId)))
835
839
  continue
@@ -8,6 +8,7 @@ import { getTraceConnectedPinComponents } from "lib/solvers/SchematicTraceLinesS
8
8
  import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
9
9
  import { getPinDirection } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver/getPinDirection"
10
10
  import { visualizeInputProblem } from "lib/solvers/SchematicTracePipelineSolver/visualizeInputProblem"
11
+ import type { CompletedTraceReroute } from "lib/solvers/TraceElbowTransitionSimplificationSolver/types"
11
12
  import type {
12
13
  InputDirectConnection,
13
14
  InputNetConnection,
@@ -24,6 +25,7 @@ import {
24
25
  import { getAnchoredNetLabelRenderedBounds } from "./getAnchoredNetLabelRenderedBounds"
25
26
  import { pushAnchoredNetLabelsAwayFromInlineLabels } from "./pushAnchoredNetLabelsAwayFromInlineLabels"
26
27
  import { pushInlineTerminalLabelsAwayFromAnchoredLabels } from "./pushInlineTerminalLabelsAwayFromAnchoredLabels"
28
+ import { restoreReroutesAroundSupersededLabels } from "./restoreReroutesAroundSupersededLabels"
27
29
 
28
30
  export const DEFAULT_INLINE_NET_LABEL_HEIGHT = 0.18
29
31
 
@@ -95,6 +97,7 @@ interface InlineNetLabelSolverInput {
95
97
  inputProblem: InputProblem
96
98
  traces: SolvedTracePath[]
97
99
  netLabelPlacements: NetLabelPlacement[]
100
+ completedReroutes?: CompletedTraceReroute[]
98
101
  }
99
102
 
100
103
  export interface InlineNetLabelOutput {
@@ -169,6 +172,7 @@ export class InlineNetLabelSolver extends BaseSolver {
169
172
  inputProblem: InputProblem
170
173
  traces: SolvedTracePath[]
171
174
  inputNetLabelPlacements: NetLabelPlacement[]
175
+ completedReroutes: CompletedTraceReroute[]
172
176
 
173
177
  inlineNetLabelPlacements: InlineNetLabelPlacement[] = []
174
178
 
@@ -190,6 +194,7 @@ export class InlineNetLabelSolver extends BaseSolver {
190
194
  this.inputProblem = input.inputProblem
191
195
  this.traces = input.traces
192
196
  this.inputNetLabelPlacements = input.netLabelPlacements
197
+ this.completedReroutes = input.completedReroutes ?? []
193
198
  this.globalConnMap = getConnectivityMapsFromInputProblem(
194
199
  this.inputProblem,
195
200
  ).netConnMap
@@ -235,6 +240,7 @@ export class InlineNetLabelSolver extends BaseSolver {
235
240
  inputProblem: this.inputProblem,
236
241
  traces: this.traces,
237
242
  netLabelPlacements: this.inputNetLabelPlacements,
243
+ completedReroutes: this.completedReroutes,
238
244
  },
239
245
  ]
240
246
  }
@@ -1066,10 +1072,19 @@ export class InlineNetLabelSolver extends BaseSolver {
1066
1072
  if (blockedGlobalConnNetIds.size === 0) {
1067
1073
  this.inlineNetLabelPlacements = activeInlinePlacements
1068
1074
  this.stats.pushedAnchoredNetLabelCount = pushed.movedLabelCount
1069
- return {
1075
+ const restored = restoreReroutesAroundSupersededLabels({
1076
+ inputProblem: this.inputProblem,
1070
1077
  traces: pushed.traces,
1071
1078
  netLabelPlacements: pushed.netLabelPlacements,
1072
1079
  inlineNetLabelPlacements: activeInlinePlacements,
1080
+ completedReroutes: this.completedReroutes,
1081
+ })
1082
+ this.stats.restoredSupersededLabelRerouteCount =
1083
+ restored.restoredTraceCount
1084
+ return {
1085
+ traces: restored.traces,
1086
+ netLabelPlacements: pushed.netLabelPlacements,
1087
+ inlineNetLabelPlacements: activeInlinePlacements,
1073
1088
  }
1074
1089
  }
1075
1090
  activeInlinePlacements = activeInlinePlacements.filter(
@@ -0,0 +1,174 @@
1
+ import type { Point } from "@tscircuit/math-utils"
2
+ import { getSegmentIntersection } from "@tscircuit/math-utils/line-intersections"
3
+ import type { NetLabelPlacement } from "lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver"
4
+ import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
5
+ import { isPathCollidingWithObstacles } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/collisions"
6
+ import { getObstacleRects } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/rect"
7
+ import { preservesLabelAnchors } from "lib/solvers/TraceCleanupSolver/sameNetRailAlignment/preservesLabelAnchors"
8
+ import { simplifyPath } from "lib/solvers/TraceCleanupSolver/simplifyPath"
9
+ import { detectTraceLabelOverlap } from "lib/solvers/TraceLabelOverlapAvoidanceSolver/detectTraceLabelOverlap"
10
+ import type { CompletedTraceReroute } from "lib/solvers/TraceElbowTransitionSimplificationSolver/types"
11
+ import type { InputProblem } from "lib/types/InputProblem"
12
+ import {
13
+ doesPathCoincideWithPaths,
14
+ doesPathCoincideWithTraces,
15
+ } from "lib/utils/doesPathCoincideWithTraces"
16
+ import { pathIntersectsRenderedLabel } from "lib/utils/pathIntersectsRenderedLabel"
17
+ import type { InlineNetLabelPlacement } from "./InlineNetLabelSolver"
18
+
19
+ const EPS = 1e-6
20
+
21
+ const getPathLength = (path: Point[]) =>
22
+ path.slice(1).reduce((length, point, pointIndex) => {
23
+ const previousPoint = path[pointIndex]!
24
+ return (
25
+ length +
26
+ Math.abs(point.x - previousPoint.x) +
27
+ Math.abs(point.y - previousPoint.y)
28
+ )
29
+ }, 0)
30
+
31
+ const pathsEqual = (first: Point[], second: Point[]) =>
32
+ first.length === second.length &&
33
+ first.every(
34
+ (point, index) =>
35
+ Math.abs(point.x - second[index]!.x) <= EPS &&
36
+ Math.abs(point.y - second[index]!.y) <= EPS,
37
+ )
38
+
39
+ const isStrictlySimpler = (candidate: Point[], current: Point[]) =>
40
+ candidate.length < current.length &&
41
+ getPathLength(candidate) <= getPathLength(current) + EPS
42
+
43
+ const getIntersectionKeys = (path: Point[], otherPath: Point[]) => {
44
+ const intersections = new Set<string>()
45
+ for (let pathIndex = 0; pathIndex < path.length - 1; pathIndex++) {
46
+ for (
47
+ let otherPathIndex = 0;
48
+ otherPathIndex < otherPath.length - 1;
49
+ otherPathIndex++
50
+ ) {
51
+ const point = getSegmentIntersection(
52
+ path[pathIndex]!,
53
+ path[pathIndex + 1]!,
54
+ otherPath[otherPathIndex]!,
55
+ otherPath[otherPathIndex + 1]!,
56
+ )
57
+ if (point) {
58
+ intersections.add(`${point.x.toFixed(6)},${point.y.toFixed(6)}`)
59
+ }
60
+ }
61
+ }
62
+ return intersections
63
+ }
64
+
65
+ const introducesNewCrossings = (
66
+ candidatePath: Point[],
67
+ currentPath: Point[],
68
+ otherPaths: Point[][],
69
+ ) =>
70
+ otherPaths.some((otherPath) => {
71
+ const currentIntersections = getIntersectionKeys(currentPath, otherPath)
72
+ const candidateIntersections = getIntersectionKeys(candidatePath, otherPath)
73
+ return [...candidateIntersections].some(
74
+ (intersection) => !currentIntersections.has(intersection),
75
+ )
76
+ })
77
+
78
+ /**
79
+ * Restores a trace's recorded pre-collision path when the anchored net label
80
+ * that caused its reroute was later replaced by an inline label.
81
+ *
82
+ * A reroute is unwound only when its current geometry still matches the
83
+ * recorded result and the original path is strictly simpler without creating
84
+ * collisions, crossings, overlaps, or detached label anchors.
85
+ */
86
+ export const restoreReroutesAroundSupersededLabels = ({
87
+ inputProblem,
88
+ traces,
89
+ netLabelPlacements,
90
+ inlineNetLabelPlacements,
91
+ completedReroutes,
92
+ }: {
93
+ inputProblem: InputProblem
94
+ traces: SolvedTracePath[]
95
+ netLabelPlacements: NetLabelPlacement[]
96
+ inlineNetLabelPlacements: InlineNetLabelPlacement[]
97
+ completedReroutes: CompletedTraceReroute[]
98
+ }) => {
99
+ const outputTraces = [...traces]
100
+ const supersededLabelGlobalConnNetIds = new Set(
101
+ inlineNetLabelPlacements.map((placement) => placement.globalConnNetId),
102
+ )
103
+ const obstacles = getObstacleRects(inputProblem)
104
+ let restoredTraceCount = 0
105
+
106
+ // A trace can be rerouted more than once. Unwind only unchanged reroutes,
107
+ // newest first, so every restoration has exact provenance.
108
+ for (const reroute of [...completedReroutes].reverse()) {
109
+ if (!supersededLabelGlobalConnNetIds.has(reroute.label.globalConnNetId)) {
110
+ continue
111
+ }
112
+
113
+ const traceIndex = outputTraces.findIndex(
114
+ (trace) => trace.mspPairId === reroute.initialTrace.mspPairId,
115
+ )
116
+ if (traceIndex < 0) continue
117
+
118
+ const currentTrace = outputTraces[traceIndex]!
119
+ const currentPath = simplifyPath(currentTrace.tracePath)
120
+ const recordedReroutePath = simplifyPath(reroute.reroutedTracePath)
121
+ if (!pathsEqual(currentPath, recordedReroutePath)) continue
122
+
123
+ const candidatePath = simplifyPath(reroute.initialTrace.tracePath)
124
+ if (!isStrictlySimpler(candidatePath, currentPath)) continue
125
+
126
+ const candidateTrace = { ...currentTrace, tracePath: candidatePath }
127
+ const otherNetTraces = outputTraces.filter(
128
+ (trace) =>
129
+ trace.mspPairId !== currentTrace.mspPairId &&
130
+ trace.globalConnNetId !== currentTrace.globalConnNetId,
131
+ )
132
+ const otherNetInlineLabels = inlineNetLabelPlacements.filter(
133
+ (label) => label.globalConnNetId !== currentTrace.globalConnNetId,
134
+ )
135
+ const otherNetInlineStubPaths = otherNetInlineLabels.flatMap((label) =>
136
+ label.stubTracePath ? [[...label.stubTracePath]] : [],
137
+ )
138
+
139
+ if (
140
+ isPathCollidingWithObstacles(candidatePath, obstacles) ||
141
+ detectTraceLabelOverlap({
142
+ traces: [candidateTrace],
143
+ netLabels: netLabelPlacements,
144
+ }).length > 0 ||
145
+ otherNetInlineLabels.some((label) =>
146
+ pathIntersectsRenderedLabel(candidatePath, label),
147
+ ) ||
148
+ doesPathCoincideWithTraces(candidatePath, otherNetTraces) ||
149
+ doesPathCoincideWithPaths(candidatePath, otherNetInlineStubPaths) ||
150
+ introducesNewCrossings(
151
+ candidatePath,
152
+ currentPath,
153
+ otherNetTraces.map((trace) => trace.tracePath),
154
+ ) ||
155
+ introducesNewCrossings(
156
+ candidatePath,
157
+ currentPath,
158
+ otherNetInlineStubPaths,
159
+ ) ||
160
+ !preservesLabelAnchors(
161
+ netLabelPlacements,
162
+ [currentTrace],
163
+ [candidateTrace],
164
+ )
165
+ ) {
166
+ continue
167
+ }
168
+
169
+ outputTraces[traceIndex] = candidateTrace
170
+ restoredTraceCount++
171
+ }
172
+
173
+ return { traces: outputTraces, restoredTraceCount }
174
+ }
@@ -1,8 +1,4 @@
1
- import {
2
- doesSegmentIntersectRect,
3
- getBoundFromCenteredRect,
4
- type Point,
5
- } from "@tscircuit/math-utils"
1
+ import type { Point } from "@tscircuit/math-utils"
6
2
  import type { GraphicsObject } from "graphics-debug"
7
3
  import { BaseSolver } from "lib/solvers/BaseSolver/BaseSolver"
8
4
  import { doesPairCrossRestrictedCenterLines } from "lib/solvers/MspConnectionPairSolver/doesPairCrossRestrictedCenterLines"
@@ -24,6 +20,7 @@ import type {
24
20
  PinId,
25
21
  } from "lib/types/InputProblem"
26
22
  import { arePinsInDifferentSchematicSections } from "lib/utils/arePinsInDifferentSchematicSections"
23
+ import { pathIntersectsRenderedLabel } from "lib/utils/pathIntersectsRenderedLabel"
27
24
  import {
28
25
  type InlineNetLabelOutput,
29
26
  type InlineNetLabelPlacement,
@@ -55,31 +52,6 @@ const MAX_ROUTED_COMPONENT_RECOVERY_PERPENDICULAR_OFFSET = 0.25
55
52
  const getCanonicalPairKey = (firstPinId: PinId, secondPinId: PinId) =>
56
53
  [firstPinId, secondPinId].sort().join("--")
57
54
 
58
- export const pathIntersectsRenderedLabel = (
59
- path: Point[],
60
- label: NetLabelPlacement | InlineNetLabelPlacement,
61
- ) => {
62
- let width = label.width
63
- let height = label.height
64
- if ("axis" in label && label.axis === "y") {
65
- width = label.height
66
- height = label.width
67
- }
68
- const bounds = getBoundFromCenteredRect({
69
- center: label.center,
70
- width,
71
- height,
72
- })
73
- for (let pathIndex = 0; pathIndex < path.length - 1; pathIndex++) {
74
- if (
75
- doesSegmentIntersectRect(path[pathIndex]!, path[pathIndex + 1]!, bounds)
76
- ) {
77
- return true
78
- }
79
- }
80
- return false
81
- }
82
-
83
55
  const getPerpendicularOffset = (firstPoint: Point, secondPoint: Point) => {
84
56
  const xDistance = Math.abs(firstPoint.x - secondPoint.x)
85
57
  const yDistance = Math.abs(firstPoint.y - secondPoint.y)
@@ -1,6 +1,7 @@
1
1
  import type { GraphicsObject, Rect } from "graphics-debug"
2
2
  import { BaseSolver } from "lib/solvers/BaseSolver/BaseSolver"
3
3
  import type { NetLabelPlacement } from "lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver"
4
+ import type { MspConnectionPairId } from "lib/solvers/MspConnectionPairSolver/MspConnectionPairSolver"
4
5
  import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
5
6
  import { visualizeInputProblem } from "lib/solvers/SchematicTracePipelineSolver/visualizeInputProblem"
6
7
  import type { InputProblem } from "lib/types/InputProblem"
@@ -13,6 +14,7 @@ interface SameNetJunctionAlignmentSolverInput {
13
14
  inputProblem: InputProblem
14
15
  traces: SolvedTracePath[]
15
16
  netLabelPlacements: NetLabelPlacement[]
17
+ netLabelConnectorTraceIds: ReadonlySet<MspConnectionPairId>
16
18
  }
17
19
 
18
20
  /** Turns separate same-net load traces into one shared rail with short junction branches. */