@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.
- package/dist/index.d.ts +5 -0
- package/dist/index.js +759 -91
- package/lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts +5 -1
- package/lib/solvers/InlineNetLabelSolver/InlineNetLabelSolver.ts +16 -1
- package/lib/solvers/InlineNetLabelSolver/restoreReroutesAroundSupersededLabels.ts +174 -0
- package/lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts +2 -30
- package/lib/solvers/SameNetJunctionAlignmentSolver/SameNetJunctionAlignmentSolver.ts +2 -0
- package/lib/solvers/SameNetJunctionAlignmentSolver/alignSameNetJunctions.ts +748 -15
- package/lib/solvers/SameNetJunctionAlignmentSolver/findNearestSharedPinExitRail.ts +140 -0
- package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +12 -5
- package/lib/utils/doesPathCoincideWithTraces.ts +17 -4
- package/lib/utils/pathIntersectsRenderedLabel.ts +33 -0
- package/package.json +1 -1
- package/site/bug-reports/bug-report-20260901T055358Z.page.tsx +4 -0
- package/site/bug-reports/bug-report-20260901T064117Z.page.tsx +4 -0
- package/site/bug-reports/bug-report-20260901T134241Z.page.tsx +4 -0
- package/tests/bug-reports/bug-report-20260707T134549Z/__snapshots__/bug-report-20260707T134549Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260707T134549Z/bug-report-20260707T134549Z.test.ts +9 -0
- package/tests/bug-reports/bug-report-20260707T230831Z/__snapshots__/bug-report-20260707T230831Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260717T042845Z/__snapshots__/bug-report-20260717T042845Z.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-20260730T061837Z/__snapshots__/bug-report-20260730T061837Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260730T061837Z/bug-report-20260730T061837Z.test.ts +8 -4
- package/tests/bug-reports/bug-report-20260804T171919Z/__snapshots__/bug-report-20260804T171919Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260805T061316Z/__snapshots__/bug-report-20260805T061316Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260806T061548Z/__snapshots__/bug-report-20260806T061548Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260825T045913Z/__snapshots__/bug-report-20260825T045913Z.snap.svg +2 -2
- package/tests/bug-reports/bug-report-20260826T072956Z/__snapshots__/bug-report-20260826T072956Z.snap.svg +6 -6
- package/tests/bug-reports/bug-report-20260901T055358Z/__snapshots__/bug-report-20260901T055358Z.snap.svg +676 -0
- package/tests/bug-reports/bug-report-20260901T055358Z/bug-report-20260901T055358Z.json +2467 -0
- package/tests/bug-reports/bug-report-20260901T055358Z/bug-report-20260901T055358Z.test.ts +59 -0
- package/tests/bug-reports/bug-report-20260901T064117Z/__snapshots__/bug-report-20260901T064117Z.snap.svg +134 -0
- package/tests/bug-reports/bug-report-20260901T064117Z/bug-report-20260901T064117Z.json +215 -0
- package/tests/bug-reports/bug-report-20260901T064117Z/bug-report-20260901T064117Z.test.ts +12 -0
- package/tests/bug-reports/bug-report-20260901T134241Z/__snapshots__/bug-report-20260901T134241Z.snap.svg +115 -0
- package/tests/bug-reports/bug-report-20260901T134241Z/bug-report-20260901T134241Z.json +359 -0
- package/tests/bug-reports/bug-report-20260901T134241Z/bug-report-20260901T134241Z.test.ts +60 -0
- package/tests/examples/__snapshots__/example51.snap.svg +2 -2
- package/tests/repros/__snapshots__/board-1273-trace-overlap-cycle.snap.svg +10 -10
- package/tests/repros/__snapshots__/board1096-usb-label-overlap-iteration.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-bq25895-cross-net-trace-overlap.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-core-ground-inline-label-fallback.snap.svg +10 -10
- package/tests/repros/__snapshots__/repro-example35-minimize-trace-crossing.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-isolated-rs485-isow7841.snap.svg +18 -18
- package/tests/repros/__snapshots__/repro-pga300-redundant-ground-traces.snap.svg +18 -18
- package/tests/repros/__snapshots__/repro-pmp11282-isolated-dcdc.snap.svg +10 -10
- package/tests/repros/__snapshots__/repro-powerbank-3v-system-power.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-ti-power-output-section.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-tida-01389-hbridge.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-tida010076-page02.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-trellis-core-gnd-net-label-overlap.snap.svg +134 -0
- package/tests/repros/__snapshots__/repro-wireless-mouse-charger-section.snap.svg +164 -0
- package/tests/repros/__snapshots__/repro161-power-section-autolayout.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro48-555-timer-vcc-rail-label.snap.svg +2 -2
- package/tests/repros/assets/repro-trellis-core-gnd-net-label-overlap.input.json +178 -0
- package/tests/repros/assets/repro-wireless-mouse-charger-section.input.json +591 -0
- package/tests/repros/repro-isolated-rs485-isow7841.test.ts +4 -1
- package/tests/repros/repro-powerbank-3v-system-power.test.ts +24 -0
- package/tests/repros/repro-tida-01389-hbridge.test.ts +24 -0
- package/tests/repros/repro-trellis-core-gnd-net-label-overlap.test.ts +73 -0
- package/tests/repros/repro-wireless-mouse-charger-section.test.ts +16 -0
- package/tests/solvers/InlineNetLabelSolver/restore-reroutes-around-superseded-labels.test.ts +186 -0
- 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
|
|
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
|
-
|
|
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. */
|