@tscircuit/schematic-trace-solver 0.0.159 → 0.0.161
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 +43 -9
- package/dist/index.js +807 -115
- package/lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts +210 -6
- package/lib/solvers/InlineNetLabelSolver/InlineNetLabelSolver.ts +536 -94
- package/lib/solvers/InlineNetLabelSolver/pushAnchoredNetLabelsAwayFromInlineLabels.ts +9 -7
- package/lib/solvers/InlineNetLabelSolver/pushInlineTerminalLabelsAwayFromAnchoredLabels.ts +295 -0
- package/lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver.ts +7 -35
- package/lib/solvers/SchematicTraceLinesSolver/getTraceConnectedPinComponents.ts +60 -0
- package/lib/solvers/TraceCleanupSolver/sameNetRailAlignment/getFixedLabelCoordinate.ts +44 -13
- package/lib/types/InputProblem.ts +5 -4
- package/package.json +1 -1
- package/tests/bug-reports/bug-report-20260706T220324Z/__snapshots__/bug-report-20260706T220324Z.snap.svg +1 -1
- package/tests/bug-reports/bug-report-20260728T144234Z/__snapshots__/bug-report-20260728T144234Z.snap.svg +1 -1
- package/tests/bug-reports/bug-report-20260728T225606Z/__snapshots__/bug-report-20260728T225606Z.snap.svg +79 -79
- package/tests/bug-reports/bug-report-20260730T061837Z/__snapshots__/bug-report-20260730T061837Z.snap.svg +85 -85
- package/tests/bug-reports/bug-report-20260731T052229Z/__snapshots__/bug-report-20260731T052229Z.snap.svg +1 -1
- package/tests/bug-reports/bug-report-20260804T095800Z/__snapshots__/bug-report-20260804T095800Z.snap.svg +163 -163
- package/tests/bug-reports/bug-report-20260804T171919Z/__snapshots__/bug-report-20260804T171919Z.snap.svg +547 -547
- package/tests/bug-reports/bug-report-20260804T225912Z/__snapshots__/bug-report-20260804T225912Z.snap.svg +13 -13
- package/tests/bug-reports/bug-report-20260805T061316Z/__snapshots__/bug-report-20260805T061316Z.snap.svg +267 -267
- package/tests/bug-reports/bug-report-20260806T061548Z/__snapshots__/bug-report-20260806T061548Z.snap.svg +267 -267
- package/tests/bug-reports/bug-report-20260806T093501Z/__snapshots__/bug-report-20260806T093501Z.snap.svg +109 -109
- package/tests/bug-reports/bug-report-20260811T075142Z/__snapshots__/bug-report-20260811T075142Z.snap.svg +1 -1
- package/tests/bug-reports/bug-report-20260815T073240Z/__snapshots__/bug-report-20260815T073240Z.snap.svg +49 -49
- package/tests/bug-reports/bug-report-20260819T091818Z/__snapshots__/bug-report-20260819T091818Z.snap.svg +1 -1
- package/tests/bug-reports/bug-report-20260825T045913Z/__snapshots__/bug-report-20260825T045913Z.snap.svg +103 -103
- package/tests/bug-reports/bug-report-20260825T103621Z/__snapshots__/bug-report-20260825T103621Z.snap.svg +103 -103
- package/tests/bug-reports/bug-report-20260826T072956Z/__snapshots__/bug-report-20260826T072956Z.snap.svg +600 -792
- package/tests/bug-reports/bug-report-20260826T072956Z/bug-report-20260826T072956Z.test.ts +66 -1
- package/tests/examples/__snapshots__/example51.snap.svg +568 -568
- package/tests/fixtures/convertSolverOutputToCircuitJson.test.ts +16 -1
- package/tests/fixtures/convertSolverOutputToCircuitJson.ts +23 -12
- package/tests/repros/__snapshots__/board-1273-trace-overlap-cycle.snap.svg +736 -736
- package/tests/repros/__snapshots__/board-15984-same-net-junction.snap.svg +79 -79
- package/tests/repros/__snapshots__/board1096-usb-label-overlap-iteration.snap.svg +127 -127
- package/tests/repros/__snapshots__/repro-bluetooth-controller-ground-decoupling-groups.snap.svg +106 -0
- package/tests/repros/__snapshots__/repro-board-589-regulator-section.snap.svg +31 -31
- package/tests/repros/__snapshots__/repro-board-648-esp12f-section.snap.svg +121 -121
- package/tests/repros/__snapshots__/repro-bq25895-cross-net-trace-overlap.snap.svg +43 -43
- package/tests/repros/__snapshots__/repro-core-555-power-cross-net-overlap.snap.svg +19 -19
- package/tests/repros/__snapshots__/repro-core-ground-inline-label-fallback.snap.svg +277 -0
- package/tests/repros/__snapshots__/repro-core-subcircuit-missing-ground.snap.svg +19 -19
- package/tests/repros/__snapshots__/repro-core-tb67s579ftg-inline-label-routing.snap.svg +7 -7
- package/tests/repros/__snapshots__/repro-dc-power-isolated-routing.snap.svg +37 -37
- package/tests/repros/__snapshots__/repro-hdc2080-ground-label-alignment.snap.svg +137 -0
- package/tests/repros/__snapshots__/repro-nrf52810-clock-routing.snap.svg +61 -61
- package/tests/repros/__snapshots__/repro-pga300-redundant-ground-traces.snap.svg +115 -115
- package/tests/repros/__snapshots__/repro-pmp11282-isolated-dcdc.snap.svg +743 -743
- package/tests/repros/__snapshots__/repro-rp2040-usb-cc2-ground-overlap.snap.svg +43 -43
- package/tests/repros/__snapshots__/repro-ti-power-output-section.snap.svg +1 -1
- package/tests/repros/__snapshots__/repro-tida010076-j4-ground-bus.snap.svg +17 -17
- package/tests/repros/__snapshots__/repro-tida010076-page02.snap.svg +1131 -1131
- package/tests/repros/__snapshots__/repro-type-c-16pin-self-connection.snap.svg +7 -7
- package/tests/repros/__snapshots__/repro-type-c-16pin-to-resistor.snap.svg +7 -7
- package/tests/repros/__snapshots__/repro-usb-power-vbus-label-detour.snap.svg +666 -666
- package/tests/repros/__snapshots__/repro161-power-section-autolayout.snap.svg +73 -73
- package/tests/repros/__snapshots__/repro48-555-timer-vcc-rail-label.snap.svg +73 -73
- package/tests/repros/assets/repro-bluetooth-controller-ground-decoupling-groups.input.json +214 -0
- package/tests/repros/assets/repro-core-ground-inline-label-fallback.input.json +863 -0
- package/tests/repros/repro-bluetooth-controller-ground-decoupling-groups.test.ts +18 -0
- package/tests/repros/repro-core-ground-inline-label-fallback.test.ts +34 -0
- package/tests/repros/repro-hdc2080-ground-label-alignment.test.ts +239 -0
- package/tests/repros/repro-tida010076-j4-ground-bus.test.ts +14 -10
- package/tests/repros/repro-tida010076-page02.test.ts +2 -2
- package/tests/repros/repro-usb-power-vbus-label-detour.test.ts +14 -0
- package/tests/solvers/InlineNetLabelSolver/__snapshots__/inline-net-label02.snap.svg +1 -1
- package/tests/solvers/InlineNetLabelSolver/multi-pin-connected-components.test.ts +252 -0
- package/tests/solvers/InlineNetLabelSolver/opposite-side-placement.test.ts +71 -0
- package/tests/solvers/InlineNetLabelSolver/push-anchored-net-labels-away.test.ts +8 -2
- package/tests/solvers/InlineNetLabelSolver/push-inline-terminal-labels-away.test.ts +91 -0
- package/tests/solvers/InlineNetLabelSolver/two-pin-terminal-stubs-atomic.test.ts +7 -1
package/dist/index.js
CHANGED
|
@@ -3181,6 +3181,50 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
|
|
|
3181
3181
|
}
|
|
3182
3182
|
};
|
|
3183
3183
|
|
|
3184
|
+
// lib/solvers/SchematicTraceLinesSolver/getTraceConnectedPinComponents.ts
|
|
3185
|
+
var getTraceConnectedPinComponents = ({
|
|
3186
|
+
pinIds,
|
|
3187
|
+
traces
|
|
3188
|
+
}) => {
|
|
3189
|
+
const adjacency = /* @__PURE__ */ new Map();
|
|
3190
|
+
for (const pinId of pinIds) adjacency.set(pinId, /* @__PURE__ */ new Set());
|
|
3191
|
+
const relevantTraces = traces.filter((trace) => {
|
|
3192
|
+
if (trace.pins.length !== 2) return false;
|
|
3193
|
+
const [firstPin, secondPin] = trace.pins;
|
|
3194
|
+
return adjacency.has(firstPin.pinId) && adjacency.has(secondPin.pinId);
|
|
3195
|
+
});
|
|
3196
|
+
for (const trace of relevantTraces) {
|
|
3197
|
+
const [firstPin, secondPin] = trace.pins;
|
|
3198
|
+
adjacency.get(firstPin.pinId).add(secondPin.pinId);
|
|
3199
|
+
adjacency.get(secondPin.pinId).add(firstPin.pinId);
|
|
3200
|
+
}
|
|
3201
|
+
const components = [];
|
|
3202
|
+
const visited = /* @__PURE__ */ new Set();
|
|
3203
|
+
for (const pinId of pinIds) {
|
|
3204
|
+
if (visited.has(pinId)) continue;
|
|
3205
|
+
const componentPinIds = [];
|
|
3206
|
+
const pending = [pinId];
|
|
3207
|
+
visited.add(pinId);
|
|
3208
|
+
while (pending.length > 0) {
|
|
3209
|
+
const currentPinId = pending.pop();
|
|
3210
|
+
componentPinIds.push(currentPinId);
|
|
3211
|
+
for (const adjacentPinId of adjacency.get(currentPinId) ?? []) {
|
|
3212
|
+
if (visited.has(adjacentPinId)) continue;
|
|
3213
|
+
visited.add(adjacentPinId);
|
|
3214
|
+
pending.push(adjacentPinId);
|
|
3215
|
+
}
|
|
3216
|
+
}
|
|
3217
|
+
const componentPinIdSet = new Set(componentPinIds);
|
|
3218
|
+
components.push({
|
|
3219
|
+
pinIds: componentPinIds,
|
|
3220
|
+
traces: relevantTraces.filter(
|
|
3221
|
+
(trace) => trace.pins.every((pin) => componentPinIdSet.has(pin.pinId))
|
|
3222
|
+
)
|
|
3223
|
+
});
|
|
3224
|
+
}
|
|
3225
|
+
return components;
|
|
3226
|
+
};
|
|
3227
|
+
|
|
3184
3228
|
// lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver.ts
|
|
3185
3229
|
var NetLabelPlacementSolver = class extends BaseSolver {
|
|
3186
3230
|
inputProblem;
|
|
@@ -3254,35 +3298,12 @@ var NetLabelPlacementSolver = class extends BaseSolver {
|
|
|
3254
3298
|
globalConnNetId
|
|
3255
3299
|
);
|
|
3256
3300
|
const pinsInNet = allIdsInNet.filter((id) => pinIdToPinMap.has(id));
|
|
3257
|
-
const
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
const
|
|
3262
|
-
|
|
3263
|
-
adj[a].add(b);
|
|
3264
|
-
adj[b].add(a);
|
|
3265
|
-
}
|
|
3266
|
-
}
|
|
3267
|
-
const visited = /* @__PURE__ */ new Set();
|
|
3268
|
-
for (const pid of pinsInNet) {
|
|
3269
|
-
if (visited.has(pid)) continue;
|
|
3270
|
-
const stack = [pid];
|
|
3271
|
-
const component = /* @__PURE__ */ new Set();
|
|
3272
|
-
visited.add(pid);
|
|
3273
|
-
while (stack.length > 0) {
|
|
3274
|
-
const u = stack.pop();
|
|
3275
|
-
component.add(u);
|
|
3276
|
-
for (const v of adj[u] ?? []) {
|
|
3277
|
-
if (!visited.has(v)) {
|
|
3278
|
-
visited.add(v);
|
|
3279
|
-
stack.push(v);
|
|
3280
|
-
}
|
|
3281
|
-
}
|
|
3282
|
-
}
|
|
3283
|
-
const compTraces = (byGlobal[globalConnNetId] ?? []).filter(
|
|
3284
|
-
(t) => component.has(t.pins[0].pinId) && component.has(t.pins[1].pinId)
|
|
3285
|
-
);
|
|
3301
|
+
for (const traceConnectedComponent of getTraceConnectedPinComponents({
|
|
3302
|
+
pinIds: pinsInNet,
|
|
3303
|
+
traces: byGlobal[globalConnNetId] ?? []
|
|
3304
|
+
})) {
|
|
3305
|
+
const component = new Set(traceConnectedComponent.pinIds);
|
|
3306
|
+
const compTraces = traceConnectedComponent.traces;
|
|
3286
3307
|
if (compTraces.length > 0) {
|
|
3287
3308
|
if (compTraces.some((trace) => trace.suppressNetLabel)) continue;
|
|
3288
3309
|
const lengthOf = (path) => {
|
|
@@ -5843,6 +5864,9 @@ var getLabelsLinkedToRailGroup = (group, netLabelPlacements, traces) => {
|
|
|
5843
5864
|
var getFixedLabelCoordinate = (group, netLabelPlacements, traces) => {
|
|
5844
5865
|
const traceMap = new Map(traces.map((trace) => [trace.mspPairId, trace]));
|
|
5845
5866
|
const groupTraceIds = new Set(group.map((segment) => segment.traceId));
|
|
5867
|
+
const groupIsWithinSingleComponent = [...groupTraceIds].every(
|
|
5868
|
+
(traceId) => traceMap.get(traceId)?.pins.every((pin) => pin.chipId === group[0].componentId) === true
|
|
5869
|
+
);
|
|
5846
5870
|
const groupHasOnlySingleRailTraces = [...groupTraceIds].every(
|
|
5847
5871
|
(traceId) => traceMap.get(traceId)?.tracePath.length === 4
|
|
5848
5872
|
);
|
|
@@ -5853,12 +5877,20 @@ var getFixedLabelCoordinate = (group, netLabelPlacements, traces) => {
|
|
|
5853
5877
|
netLabelPlacements,
|
|
5854
5878
|
traces
|
|
5855
5879
|
);
|
|
5856
|
-
const
|
|
5857
|
-
|
|
5880
|
+
const labelsOrientedAlongRail = new Set(
|
|
5881
|
+
linkedLabels.filter(
|
|
5882
|
+
(label) => orientation === "vertical" && (label.orientation === "y+" || label.orientation === "y-") || orientation === "horizontal" && (label.orientation === "x+" || label.orientation === "x-")
|
|
5883
|
+
)
|
|
5884
|
+
);
|
|
5885
|
+
const anchoringLabels = linkedLabels.filter((label) => {
|
|
5886
|
+
if (label.orientation !== group[0].componentFacingDirection && (!groupIsWithinSingleComponent || !labelsOrientedAlongRail.has(label))) {
|
|
5887
|
+
return false;
|
|
5888
|
+
}
|
|
5889
|
+
return label.mspConnectionPairIds.some((traceId) => {
|
|
5858
5890
|
const trace = traceMap.get(traceId);
|
|
5859
5891
|
return trace && tracePathContainsPoint(trace.tracePath, label.anchorPoint);
|
|
5860
|
-
})
|
|
5861
|
-
);
|
|
5892
|
+
});
|
|
5893
|
+
});
|
|
5862
5894
|
const coordinates = getDistinctCoordinates(
|
|
5863
5895
|
anchoringLabels.map(
|
|
5864
5896
|
(label) => orientation === "vertical" ? label.anchorPoint.x : label.anchorPoint.y
|
|
@@ -5875,12 +5907,21 @@ var getFixedLabelCoordinate = (group, netLabelPlacements, traces) => {
|
|
|
5875
5907
|
)
|
|
5876
5908
|
);
|
|
5877
5909
|
if (labelIsAnchoredToRoutedBackbone) return coordinate;
|
|
5910
|
+
if (anchoringLabels.some((label) => labelsOrientedAlongRail.has(label))) {
|
|
5911
|
+
const railGroupSpan = Math.max(...group.map((segment) => segment.maxAlong)) - Math.min(...group.map((segment) => segment.minAlong));
|
|
5912
|
+
const coordinateIsLocalToRailGroup = group.every(
|
|
5913
|
+
(segment) => Math.abs(segment.coordinate - coordinate) <= railGroupSpan + RAIL_ALIGNMENT_EPSILON
|
|
5914
|
+
);
|
|
5915
|
+
if (coordinateIsLocalToRailGroup) return coordinate;
|
|
5916
|
+
return null;
|
|
5917
|
+
}
|
|
5878
5918
|
const coordinateIsLocalToEveryTrace = group.every((segment) => {
|
|
5879
5919
|
const trace = traceMap.get(segment.traceId);
|
|
5880
5920
|
if (!trace) return false;
|
|
5881
5921
|
return Math.abs(segment.coordinate - coordinate) <= distance4(trace.pins[0], trace.pins[1]) + RAIL_ALIGNMENT_EPSILON;
|
|
5882
5922
|
});
|
|
5883
|
-
|
|
5923
|
+
if (coordinateIsLocalToEveryTrace) return coordinate;
|
|
5924
|
+
return null;
|
|
5884
5925
|
};
|
|
5885
5926
|
|
|
5886
5927
|
// lib/solvers/TraceCleanupSolver/sameNetRailAlignment/moveRailSegments.ts
|
|
@@ -8918,6 +8959,9 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8918
8959
|
const orientations = this.getAvailableOrientations(label);
|
|
8919
8960
|
if (orientations.length === 0) return false;
|
|
8920
8961
|
if (!orientations.includes(label.orientation)) return true;
|
|
8962
|
+
if (this.getTextBlockedMultiPinRailTraces(label, orientations[0])) {
|
|
8963
|
+
return true;
|
|
8964
|
+
}
|
|
8921
8965
|
if (!this.crowdedPortOnlyLabelIndices.has(labelIndex)) return false;
|
|
8922
8966
|
const bounds = getRectBounds(label.center, label.width, label.height);
|
|
8923
8967
|
return this.outputNetLabelPlacements.some((otherLabel, otherIndex) => {
|
|
@@ -9039,8 +9083,34 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
9039
9083
|
);
|
|
9040
9084
|
const isTwoPinNet = netConnection?.pinIds.length === 2;
|
|
9041
9085
|
const isDistanceSplitVerticalRail = (netConnection?.pinIds.length ?? 0) > 2 && isYOrientation(requiredOrientation) && this.hasPortOnlyLabelOnSameNet(label);
|
|
9086
|
+
const textBlockedMultiPinRailTraces = this.getTextBlockedMultiPinRailTraces(
|
|
9087
|
+
label,
|
|
9088
|
+
requiredOrientation
|
|
9089
|
+
);
|
|
9042
9090
|
const isPairedSameSidePowerRail = isYOrientation(requiredOrientation) && this.hasOppositeVerticalRailOnSameChipSide(label, requiredOrientation);
|
|
9091
|
+
if (textBlockedMultiPinRailTraces) {
|
|
9092
|
+
const nearbyCandidate = this.findValidNearbyRailCandidate(
|
|
9093
|
+
label,
|
|
9094
|
+
requiredOrientation,
|
|
9095
|
+
labelIndex,
|
|
9096
|
+
textBlockedMultiPinRailTraces
|
|
9097
|
+
);
|
|
9098
|
+
if (nearbyCandidate) return nearbyCandidate;
|
|
9099
|
+
}
|
|
9043
9100
|
if (orientations.length === 1 && isYOrientation(requiredOrientation) && this.isOutwardHorizontalFallback(label) && this.hasTraceContinuingInOrientation(label, requiredOrientation) && (isDistanceSplitVerticalRail || isPairedSameSidePowerRail)) {
|
|
9101
|
+
const hostRailCandidate = this.findValidTraceAnchorCandidate(
|
|
9102
|
+
label,
|
|
9103
|
+
requiredOrientation,
|
|
9104
|
+
labelIndex
|
|
9105
|
+
);
|
|
9106
|
+
if (hostRailCandidate) {
|
|
9107
|
+
const canUseHostRail = this.canPlaceVerticalLabelOnHostRail(
|
|
9108
|
+
hostRailCandidate,
|
|
9109
|
+
label
|
|
9110
|
+
);
|
|
9111
|
+
if (canUseHostRail) return hostRailCandidate;
|
|
9112
|
+
hostRailCandidate.selected = false;
|
|
9113
|
+
}
|
|
9044
9114
|
const traceAnchorCandidate2 = this.findValidOutwardTraceAnchorCandidate(
|
|
9045
9115
|
label,
|
|
9046
9116
|
requiredOrientation,
|
|
@@ -9474,14 +9544,21 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
9474
9544
|
maxSearchDistance,
|
|
9475
9545
|
outwardDistance,
|
|
9476
9546
|
phase = "shift",
|
|
9477
|
-
stopOnTraceCollision = true
|
|
9547
|
+
stopOnTraceCollision = true,
|
|
9548
|
+
connectorSource,
|
|
9549
|
+
startDistance = LABEL_SEARCH_STEP
|
|
9478
9550
|
} = params;
|
|
9479
|
-
for (let distance7 =
|
|
9551
|
+
for (let distance7 = startDistance; distance7 <= maxSearchDistance + EPS12; distance7 += LABEL_SEARCH_STEP) {
|
|
9480
9552
|
const anchorPoint = {
|
|
9481
9553
|
x: baseAnchor.x + direction.x * distance7,
|
|
9482
9554
|
y: baseAnchor.y + direction.y * distance7
|
|
9483
9555
|
};
|
|
9484
|
-
const candidate = this.createCandidate(
|
|
9556
|
+
const candidate = this.createCandidate(
|
|
9557
|
+
label,
|
|
9558
|
+
anchorPoint,
|
|
9559
|
+
orientation,
|
|
9560
|
+
connectorSource
|
|
9561
|
+
);
|
|
9485
9562
|
const result = this.evaluateCandidate(
|
|
9486
9563
|
candidate,
|
|
9487
9564
|
label,
|
|
@@ -9857,6 +9934,113 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
9857
9934
|
const chipSide = this.getChipSideForPoint(label.anchorPoint);
|
|
9858
9935
|
return chipSide === "left" && label.orientation === "x-" || chipSide === "right" && label.orientation === "x+";
|
|
9859
9936
|
}
|
|
9937
|
+
canPlaceVerticalLabelOnHostRail(candidate, label) {
|
|
9938
|
+
const isOnHostRail = label.mspConnectionPairIds.some((traceId) => {
|
|
9939
|
+
const trace = this.traceMap[traceId];
|
|
9940
|
+
return trace && tracePathContainsPoint(trace.tracePath, candidate.anchorPoint);
|
|
9941
|
+
});
|
|
9942
|
+
if (!isOnHostRail) return false;
|
|
9943
|
+
const hostPin = this.pinMap[label.pinIds[0]];
|
|
9944
|
+
if (!hostPin) return false;
|
|
9945
|
+
if (label.pinIds.some(
|
|
9946
|
+
(pinId) => this.pinMap[pinId]?.chipId !== hostPin.chipId
|
|
9947
|
+
)) {
|
|
9948
|
+
return false;
|
|
9949
|
+
}
|
|
9950
|
+
const chip = this.chipObstacleSpatialIndex.chips.find(
|
|
9951
|
+
(chip2) => chip2.chipId === hostPin.chipId
|
|
9952
|
+
);
|
|
9953
|
+
if (!chip) return false;
|
|
9954
|
+
const labelBounds = getRectBounds(
|
|
9955
|
+
candidate.center,
|
|
9956
|
+
candidate.width,
|
|
9957
|
+
candidate.height
|
|
9958
|
+
);
|
|
9959
|
+
if (labelBounds.minY < chip.bounds.minY - EPS12 || labelBounds.maxY > chip.bounds.maxY + EPS12) {
|
|
9960
|
+
return false;
|
|
9961
|
+
}
|
|
9962
|
+
if (candidate.anchorPoint.x >= chip.bounds.minX - EPS12 && candidate.anchorPoint.x <= chip.bounds.maxX + EPS12) {
|
|
9963
|
+
return false;
|
|
9964
|
+
}
|
|
9965
|
+
return chip.pins.every(
|
|
9966
|
+
(pin) => label.pinIds.includes(pin.pinId) || pin.y <= labelBounds.minY + EPS12 || pin.y >= labelBounds.maxY - EPS12
|
|
9967
|
+
);
|
|
9968
|
+
}
|
|
9969
|
+
getTextBlockedMultiPinRailTraces(label, orientation) {
|
|
9970
|
+
if (!isYOrientation(orientation)) return null;
|
|
9971
|
+
const componentId = this.pinMap[label.pinIds[0]]?.chipId;
|
|
9972
|
+
const localTraces = Object.values(this.traceMap).filter(
|
|
9973
|
+
(trace) => trace.globalConnNetId === label.globalConnNetId && trace.pins.every((pin) => pin.chipId === componentId)
|
|
9974
|
+
);
|
|
9975
|
+
const connectedPinIds = new Set(label.pinIds);
|
|
9976
|
+
const connectedTraces = /* @__PURE__ */ new Set();
|
|
9977
|
+
for (let changed = true; changed; ) {
|
|
9978
|
+
changed = false;
|
|
9979
|
+
for (const trace of localTraces) {
|
|
9980
|
+
if (connectedTraces.has(trace)) continue;
|
|
9981
|
+
if (!trace.pinIds.some((pinId) => connectedPinIds.has(pinId))) continue;
|
|
9982
|
+
connectedTraces.add(trace);
|
|
9983
|
+
for (const pinId of trace.pinIds) connectedPinIds.add(pinId);
|
|
9984
|
+
changed = true;
|
|
9985
|
+
}
|
|
9986
|
+
}
|
|
9987
|
+
if (connectedPinIds.size <= 3) return null;
|
|
9988
|
+
const pins = [...connectedPinIds].map((pinId) => this.pinMap[pinId]);
|
|
9989
|
+
const direction = dir(orientation);
|
|
9990
|
+
const pinX = pins[0].x;
|
|
9991
|
+
if (pins.some((pin) => Math.abs(pin.x - pinX) > EPS12)) return null;
|
|
9992
|
+
const sidePins = this.inputProblem.chips.find((chip) => chip.chipId === componentId).pins.filter((pin) => Math.abs(pin.x - pinX) <= EPS12);
|
|
9993
|
+
const minY = Math.min(...pins.map((pin) => pin.y));
|
|
9994
|
+
const maxY = Math.max(...pins.map((pin) => pin.y));
|
|
9995
|
+
if (sidePins.some(
|
|
9996
|
+
(pin) => pin.y >= minY - EPS12 && pin.y <= maxY + EPS12 && !connectedPinIds.has(pin.pinId)
|
|
9997
|
+
) || orientation === "y-" && minY > Math.min(...sidePins.map((pin) => pin.y)) + EPS12 || orientation === "y+" && maxY < Math.max(...sidePins.map((pin) => pin.y)) - EPS12) {
|
|
9998
|
+
return null;
|
|
9999
|
+
}
|
|
10000
|
+
const outerPinPosition = Math.max(
|
|
10001
|
+
...pins.map((pin) => pin.x * direction.x + pin.y * direction.y)
|
|
10002
|
+
);
|
|
10003
|
+
const blockedByText = (this.inputProblem.textBoxes ?? []).some(
|
|
10004
|
+
(textBox) => textBox.chipId === componentId && textBox.center.x * direction.x + textBox.center.y * direction.y > outerPinPosition + EPS12
|
|
10005
|
+
);
|
|
10006
|
+
return blockedByText ? [...connectedTraces] : null;
|
|
10007
|
+
}
|
|
10008
|
+
findValidNearbyRailCandidate(label, orientation, labelIndex, localTraces) {
|
|
10009
|
+
if (!isYOrientation(orientation)) return null;
|
|
10010
|
+
const direction = dir(orientation);
|
|
10011
|
+
const connectorY = [
|
|
10012
|
+
...new Set(localTraces.flatMap((trace) => trace.pinIds))
|
|
10013
|
+
].map((pinId) => this.pinMap[pinId]).sort((a, b) => b.y * direction.y - a.y * direction.y)[0]?.y;
|
|
10014
|
+
if (connectorY === void 0) return null;
|
|
10015
|
+
const pinX = this.pinMap[label.pinIds[0]].x;
|
|
10016
|
+
const railXs = [
|
|
10017
|
+
...new Set(
|
|
10018
|
+
localTraces.flatMap((trace) => trace.tracePath.map((point) => point.x))
|
|
10019
|
+
)
|
|
10020
|
+
].filter((x) => Math.abs(x - pinX) > EPS12).sort((a, b) => Math.abs(a - pinX) - Math.abs(b - pinX));
|
|
10021
|
+
for (const x of railXs) {
|
|
10022
|
+
const connectorSource = { x, y: connectorY };
|
|
10023
|
+
if (!Object.values(this.traceMap).some(
|
|
10024
|
+
(trace) => trace.globalConnNetId === label.globalConnNetId && tracePathContainsPoint(trace.tracePath, connectorSource)
|
|
10025
|
+
)) {
|
|
10026
|
+
continue;
|
|
10027
|
+
}
|
|
10028
|
+
const candidate = this.findValidCandidateInShiftColumn({
|
|
10029
|
+
label,
|
|
10030
|
+
labelIndex,
|
|
10031
|
+
orientation,
|
|
10032
|
+
direction,
|
|
10033
|
+
baseAnchor: connectorSource,
|
|
10034
|
+
maxSearchDistance: this.maxSearchDistance,
|
|
10035
|
+
outwardDistance: 0,
|
|
10036
|
+
stopOnTraceCollision: false,
|
|
10037
|
+
connectorSource,
|
|
10038
|
+
startDistance: 0
|
|
10039
|
+
});
|
|
10040
|
+
if (candidate) return candidate;
|
|
10041
|
+
}
|
|
10042
|
+
return null;
|
|
10043
|
+
}
|
|
9860
10044
|
hasPortOnlyLabelOnSameNet(label) {
|
|
9861
10045
|
return this.outputNetLabelPlacements.some(
|
|
9862
10046
|
(otherLabel) => otherLabel !== label && otherLabel.globalConnNetId === label.globalConnNetId && this.isPortOnlyLabel(otherLabel)
|
|
@@ -13695,7 +13879,7 @@ var pushAnchoredNetLabelsAwayFromInlineLabels = ({
|
|
|
13695
13879
|
const connectorObstructed = inlineBounds.some(
|
|
13696
13880
|
(bounds) => pathIntersectsBounds(connector.tracePath, bounds)
|
|
13697
13881
|
) || inputProblem.chips.some(
|
|
13698
|
-
(chip) => pathIntersectsBounds(connector.tracePath, {
|
|
13882
|
+
(chip) => !ownerChipIds.has(chip.chipId) && pathIntersectsBounds(connector.tracePath, {
|
|
13699
13883
|
minX: chip.center.x - chip.width / 2,
|
|
13700
13884
|
maxX: chip.center.x + chip.width / 2,
|
|
13701
13885
|
minY: chip.center.y - chip.height / 2,
|
|
@@ -13732,20 +13916,247 @@ var pushAnchoredNetLabelsAwayFromInlineLabels = ({
|
|
|
13732
13916
|
};
|
|
13733
13917
|
};
|
|
13734
13918
|
|
|
13919
|
+
// lib/solvers/InlineNetLabelSolver/pushInlineTerminalLabelsAwayFromAnchoredLabels.ts
|
|
13920
|
+
var LABEL_CLEARANCE3 = 0.05;
|
|
13921
|
+
var MAX_OUTWARD_DISTANCE2 = 5;
|
|
13922
|
+
var getStubDirection2 = (path) => {
|
|
13923
|
+
const [start, end] = path;
|
|
13924
|
+
if (Math.abs(end.x - start.x) >= Math.abs(end.y - start.y)) {
|
|
13925
|
+
return end.x >= start.x ? "x+" : "x-";
|
|
13926
|
+
}
|
|
13927
|
+
return end.y >= start.y ? "y+" : "y-";
|
|
13928
|
+
};
|
|
13929
|
+
var getLabelBounds3 = (placement) => {
|
|
13930
|
+
const renderedWidth = placement.axis === "y" ? placement.height : placement.width;
|
|
13931
|
+
const renderedHeight = placement.axis === "y" ? placement.width : placement.height;
|
|
13932
|
+
return {
|
|
13933
|
+
minX: placement.center.x - renderedWidth / 2,
|
|
13934
|
+
maxX: placement.center.x + renderedWidth / 2,
|
|
13935
|
+
minY: placement.center.y - renderedHeight / 2,
|
|
13936
|
+
maxY: placement.center.y + renderedHeight / 2
|
|
13937
|
+
};
|
|
13938
|
+
};
|
|
13939
|
+
var getPathBounds2 = (path) => ({
|
|
13940
|
+
minX: Math.min(...path.map((point) => point.x)),
|
|
13941
|
+
maxX: Math.max(...path.map((point) => point.x)),
|
|
13942
|
+
minY: Math.min(...path.map((point) => point.y)),
|
|
13943
|
+
maxY: Math.max(...path.map((point) => point.y))
|
|
13944
|
+
});
|
|
13945
|
+
var doesPathIntersectBounds2 = (path, bounds) => {
|
|
13946
|
+
for (let index = 0; index < path.length - 1; index++) {
|
|
13947
|
+
if (boundsOverlap(getPathBounds2([path[index], path[index + 1]]), bounds)) {
|
|
13948
|
+
return true;
|
|
13949
|
+
}
|
|
13950
|
+
}
|
|
13951
|
+
return false;
|
|
13952
|
+
};
|
|
13953
|
+
var shiftPoint = (point, direction, distance7) => {
|
|
13954
|
+
switch (direction) {
|
|
13955
|
+
case "x+":
|
|
13956
|
+
return { x: point.x + distance7, y: point.y };
|
|
13957
|
+
case "x-":
|
|
13958
|
+
return { x: point.x - distance7, y: point.y };
|
|
13959
|
+
case "y+":
|
|
13960
|
+
return { x: point.x, y: point.y + distance7 };
|
|
13961
|
+
case "y-":
|
|
13962
|
+
return { x: point.x, y: point.y - distance7 };
|
|
13963
|
+
}
|
|
13964
|
+
};
|
|
13965
|
+
var shiftTerminalPlacement = (placement, direction, distance7) => {
|
|
13966
|
+
const [start, end] = placement.stubTracePath;
|
|
13967
|
+
const shiftedEnd = shiftPoint(end, direction, distance7);
|
|
13968
|
+
return {
|
|
13969
|
+
...placement,
|
|
13970
|
+
stubTracePath: [start, shiftedEnd],
|
|
13971
|
+
anchorPoint: shiftPoint(placement.anchorPoint, direction, distance7),
|
|
13972
|
+
center: shiftPoint(placement.center, direction, distance7)
|
|
13973
|
+
};
|
|
13974
|
+
};
|
|
13975
|
+
var getRequiredOutwardDistance2 = (movingBounds, obstacleBounds, direction) => {
|
|
13976
|
+
switch (direction) {
|
|
13977
|
+
case "x+":
|
|
13978
|
+
return obstacleBounds.maxX - movingBounds.minX + LABEL_CLEARANCE3;
|
|
13979
|
+
case "x-":
|
|
13980
|
+
return movingBounds.maxX - obstacleBounds.minX + LABEL_CLEARANCE3;
|
|
13981
|
+
case "y+":
|
|
13982
|
+
return obstacleBounds.maxY - movingBounds.minY + LABEL_CLEARANCE3;
|
|
13983
|
+
case "y-":
|
|
13984
|
+
return movingBounds.maxY - obstacleBounds.minY + LABEL_CLEARANCE3;
|
|
13985
|
+
}
|
|
13986
|
+
};
|
|
13987
|
+
var pushInlineTerminalLabelsAwayFromAnchoredLabels = ({
|
|
13988
|
+
inputProblem,
|
|
13989
|
+
traces,
|
|
13990
|
+
anchoredNetLabelPlacements,
|
|
13991
|
+
inlineNetLabelPlacements
|
|
13992
|
+
}) => {
|
|
13993
|
+
const chipIdByPinId = /* @__PURE__ */ new Map();
|
|
13994
|
+
for (const chip of inputProblem.chips) {
|
|
13995
|
+
for (const pin of chip.pins) chipIdByPinId.set(pin.pinId, chip.chipId);
|
|
13996
|
+
}
|
|
13997
|
+
const groups = /* @__PURE__ */ new Map();
|
|
13998
|
+
for (const [
|
|
13999
|
+
placementIndex,
|
|
14000
|
+
placement
|
|
14001
|
+
] of inlineNetLabelPlacements.entries()) {
|
|
14002
|
+
if (!placement.stubTracePath || placement.pinIds.length !== 1) continue;
|
|
14003
|
+
const direction = getStubDirection2(placement.stubTracePath);
|
|
14004
|
+
const ownerChipId = chipIdByPinId.get(placement.pinIds[0]);
|
|
14005
|
+
const groupKey = `${ownerChipId ?? placement.pinIds[0]}::${direction}`;
|
|
14006
|
+
const group = groups.get(groupKey) ?? [];
|
|
14007
|
+
group.push({ placementIndex, placement, direction, ownerChipId });
|
|
14008
|
+
groups.set(groupKey, group);
|
|
14009
|
+
}
|
|
14010
|
+
const outputPlacements = [...inlineNetLabelPlacements];
|
|
14011
|
+
let movedGroupCount = 0;
|
|
14012
|
+
for (const group of groups.values()) {
|
|
14013
|
+
const groupPlacementIndices = new Set(
|
|
14014
|
+
group.map(({ placementIndex }) => placementIndex)
|
|
14015
|
+
);
|
|
14016
|
+
const fixedInlinePlacements = outputPlacements.filter(
|
|
14017
|
+
(_, placementIndex) => !groupPlacementIndices.has(placementIndex)
|
|
14018
|
+
);
|
|
14019
|
+
const direction = group[0].direction;
|
|
14020
|
+
let distance7 = 0;
|
|
14021
|
+
for (let iteration = 0; iteration <= anchoredNetLabelPlacements.length; iteration++) {
|
|
14022
|
+
let requiredAdditionalDistance = 0;
|
|
14023
|
+
for (const { placement } of group) {
|
|
14024
|
+
const shiftedPlacement = shiftTerminalPlacement(
|
|
14025
|
+
placement,
|
|
14026
|
+
direction,
|
|
14027
|
+
distance7
|
|
14028
|
+
);
|
|
14029
|
+
const shiftedBounds = getLabelBounds3(shiftedPlacement);
|
|
14030
|
+
for (const anchoredPlacement of anchoredNetLabelPlacements) {
|
|
14031
|
+
if (anchoredPlacement.globalConnNetId === placement.globalConnNetId) {
|
|
14032
|
+
continue;
|
|
14033
|
+
}
|
|
14034
|
+
const anchoredBounds = getLabelBounds3(anchoredPlacement);
|
|
14035
|
+
if (!boundsOverlap(shiftedBounds, anchoredBounds)) continue;
|
|
14036
|
+
requiredAdditionalDistance = Math.max(
|
|
14037
|
+
requiredAdditionalDistance,
|
|
14038
|
+
getRequiredOutwardDistance2(
|
|
14039
|
+
shiftedBounds,
|
|
14040
|
+
anchoredBounds,
|
|
14041
|
+
direction
|
|
14042
|
+
)
|
|
14043
|
+
);
|
|
14044
|
+
}
|
|
14045
|
+
}
|
|
14046
|
+
if (requiredAdditionalDistance <= 0) break;
|
|
14047
|
+
distance7 += requiredAdditionalDistance;
|
|
14048
|
+
}
|
|
14049
|
+
if (distance7 <= 0 || distance7 > MAX_OUTWARD_DISTANCE2) continue;
|
|
14050
|
+
const proposals = group.map(
|
|
14051
|
+
({ placement }) => shiftTerminalPlacement(placement, direction, distance7)
|
|
14052
|
+
);
|
|
14053
|
+
const hasConflict = proposals.some((proposal, proposalIndex) => {
|
|
14054
|
+
const originalPlacement = group[proposalIndex].placement;
|
|
14055
|
+
const originalEnd = originalPlacement.stubTracePath[1];
|
|
14056
|
+
const shiftedEnd = proposal.stubTracePath[1];
|
|
14057
|
+
const addedStubSegment = [originalEnd, shiftedEnd];
|
|
14058
|
+
const labelBounds = getLabelBounds3(proposal);
|
|
14059
|
+
const ownerChipId = group[proposalIndex].ownerChipId;
|
|
14060
|
+
if (anchoredNetLabelPlacements.some((anchoredPlacement) => {
|
|
14061
|
+
if (anchoredPlacement.globalConnNetId === proposal.globalConnNetId) {
|
|
14062
|
+
return false;
|
|
14063
|
+
}
|
|
14064
|
+
const anchoredBounds = getLabelBounds3(anchoredPlacement);
|
|
14065
|
+
return boundsOverlap(labelBounds, anchoredBounds) || doesPathIntersectBounds2(addedStubSegment, anchoredBounds);
|
|
14066
|
+
})) {
|
|
14067
|
+
return true;
|
|
14068
|
+
}
|
|
14069
|
+
for (const chip of inputProblem.chips) {
|
|
14070
|
+
if (chip.chipId === ownerChipId) continue;
|
|
14071
|
+
const chipBounds = {
|
|
14072
|
+
minX: chip.center.x - chip.width / 2,
|
|
14073
|
+
maxX: chip.center.x + chip.width / 2,
|
|
14074
|
+
minY: chip.center.y - chip.height / 2,
|
|
14075
|
+
maxY: chip.center.y + chip.height / 2
|
|
14076
|
+
};
|
|
14077
|
+
if (boundsOverlap(labelBounds, chipBounds) || doesPathIntersectBounds2(addedStubSegment, chipBounds)) {
|
|
14078
|
+
return true;
|
|
14079
|
+
}
|
|
14080
|
+
}
|
|
14081
|
+
for (const textBox of inputProblem.textBoxes ?? []) {
|
|
14082
|
+
const textBounds = getTextBoxBounds(textBox);
|
|
14083
|
+
if (boundsOverlap(labelBounds, textBounds) || doesPathIntersectBounds2(addedStubSegment, textBounds)) {
|
|
14084
|
+
return true;
|
|
14085
|
+
}
|
|
14086
|
+
}
|
|
14087
|
+
for (const trace of traces) {
|
|
14088
|
+
if (trace.globalConnNetId === proposal.globalConnNetId) continue;
|
|
14089
|
+
if (doesPathIntersectBounds2(trace.tracePath, labelBounds) || doesPathIntersectBounds2(
|
|
14090
|
+
trace.tracePath,
|
|
14091
|
+
getPathBounds2(addedStubSegment)
|
|
14092
|
+
)) {
|
|
14093
|
+
return true;
|
|
14094
|
+
}
|
|
14095
|
+
}
|
|
14096
|
+
for (const fixedPlacement of fixedInlinePlacements) {
|
|
14097
|
+
const fixedBounds = getLabelBounds3(fixedPlacement);
|
|
14098
|
+
if (boundsOverlap(labelBounds, fixedBounds) || doesPathIntersectBounds2(addedStubSegment, fixedBounds) || fixedPlacement.stubTracePath && doesPathIntersectBounds2(fixedPlacement.stubTracePath, labelBounds)) {
|
|
14099
|
+
return true;
|
|
14100
|
+
}
|
|
14101
|
+
}
|
|
14102
|
+
return false;
|
|
14103
|
+
});
|
|
14104
|
+
if (hasConflict) continue;
|
|
14105
|
+
for (const [groupIndex, { placementIndex }] of group.entries()) {
|
|
14106
|
+
outputPlacements[placementIndex] = proposals[groupIndex];
|
|
14107
|
+
}
|
|
14108
|
+
movedGroupCount++;
|
|
14109
|
+
}
|
|
14110
|
+
return {
|
|
14111
|
+
inlineNetLabelPlacements: outputPlacements,
|
|
14112
|
+
movedGroupCount
|
|
14113
|
+
};
|
|
14114
|
+
};
|
|
14115
|
+
|
|
13735
14116
|
// lib/solvers/InlineNetLabelSolver/InlineNetLabelSolver.ts
|
|
13736
14117
|
var DEFAULT_INLINE_NET_LABEL_HEIGHT = 0.18;
|
|
13737
14118
|
var INLINE_NET_LABEL_TRACE_MARGIN = 0.05;
|
|
13738
14119
|
var INLINE_NET_LABEL_STUB_TRACE_CLEARANCE = 0.05;
|
|
13739
14120
|
var INLINE_NET_LABEL_MAX_SPAN_JOG = 0.4;
|
|
14121
|
+
var AVAILABLE_NET_ORIENTATION_TRACE_PREFIX = "available-net-orientation-";
|
|
14122
|
+
var isGeneratedAnchoredLabelConnector = (trace) => trace.mspPairId.startsWith(AVAILABLE_NET_ORIENTATION_TRACE_PREFIX);
|
|
13740
14123
|
var getPinPairKey2 = (pinIds) => [...pinIds].sort().join("::");
|
|
14124
|
+
var getTraceLength2 = (trace) => {
|
|
14125
|
+
let length = 0;
|
|
14126
|
+
for (let index = 0; index < trace.tracePath.length - 1; index++) {
|
|
14127
|
+
const start = trace.tracePath[index];
|
|
14128
|
+
const end = trace.tracePath[index + 1];
|
|
14129
|
+
length += Math.abs(end.x - start.x) + Math.abs(end.y - start.y);
|
|
14130
|
+
}
|
|
14131
|
+
return length;
|
|
14132
|
+
};
|
|
14133
|
+
var setsEqual = (first, second) => first.size === second.size && [...first].every((value) => second.has(value));
|
|
14134
|
+
var getInlinePlacementBounds = (placement) => {
|
|
14135
|
+
const renderedWidth = placement.axis === "y" ? placement.height : placement.width;
|
|
14136
|
+
const renderedHeight = placement.axis === "y" ? placement.width : placement.height;
|
|
14137
|
+
return {
|
|
14138
|
+
minX: placement.center.x - renderedWidth / 2,
|
|
14139
|
+
maxX: placement.center.x + renderedWidth / 2,
|
|
14140
|
+
minY: placement.center.y - renderedHeight / 2,
|
|
14141
|
+
maxY: placement.center.y + renderedHeight / 2
|
|
14142
|
+
};
|
|
14143
|
+
};
|
|
14144
|
+
var getAnchoredPlacementBounds = (placement) => ({
|
|
14145
|
+
minX: placement.center.x - placement.width / 2,
|
|
14146
|
+
maxX: placement.center.x + placement.width / 2,
|
|
14147
|
+
minY: placement.center.y - placement.height / 2,
|
|
14148
|
+
maxY: placement.center.y + placement.height / 2
|
|
14149
|
+
});
|
|
13741
14150
|
var InlineNetLabelSolver = class extends BaseSolver {
|
|
13742
14151
|
inputProblem;
|
|
13743
14152
|
traces;
|
|
13744
14153
|
inputNetLabelPlacements;
|
|
13745
14154
|
inlineNetLabelPlacements = [];
|
|
13746
|
-
/** Eligible
|
|
14155
|
+
/** Eligible connections still waiting to be processed. */
|
|
13747
14156
|
queuedConnections;
|
|
13748
14157
|
tracesByPinPairKey;
|
|
14158
|
+
globalConnMap;
|
|
14159
|
+
supersededTraceIdsByGlobalConnNetId = /* @__PURE__ */ new Map();
|
|
13749
14160
|
hasAlignedPortOnlyStubs = false;
|
|
13750
14161
|
postProcessedOutput;
|
|
13751
14162
|
constructor(input) {
|
|
@@ -13753,16 +14164,26 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13753
14164
|
this.inputProblem = input.inputProblem;
|
|
13754
14165
|
this.traces = input.traces;
|
|
13755
14166
|
this.inputNetLabelPlacements = input.netLabelPlacements;
|
|
14167
|
+
this.globalConnMap = getConnectivityMapsFromInputProblem(
|
|
14168
|
+
this.inputProblem
|
|
14169
|
+
).netConnMap;
|
|
13756
14170
|
this.queuedConnections = [
|
|
13757
14171
|
...this.inputProblem.directConnections.filter(
|
|
13758
14172
|
(connection) => connection.allowInlineNetLabel && connection.netId
|
|
13759
|
-
)
|
|
14173
|
+
).map((connection) => ({
|
|
14174
|
+
kind: "direct_connection",
|
|
14175
|
+
connection
|
|
14176
|
+
})),
|
|
13760
14177
|
...this.inputProblem.netConnections.filter(
|
|
13761
|
-
(connection) => connection.allowInlineNetLabel && connection.pinIds.length >= 1 && connection.
|
|
13762
|
-
)
|
|
14178
|
+
(connection) => connection.allowInlineNetLabel && connection.pinIds.length >= 1 && connection.netId
|
|
14179
|
+
).map((connection) => ({
|
|
14180
|
+
kind: "net_connection",
|
|
14181
|
+
connection
|
|
14182
|
+
}))
|
|
13763
14183
|
];
|
|
13764
14184
|
this.tracesByPinPairKey = /* @__PURE__ */ new Map();
|
|
13765
14185
|
for (const trace of this.traces) {
|
|
14186
|
+
if (isGeneratedAnchoredLabelConnector(trace)) continue;
|
|
13766
14187
|
const key = getPinPairKey2(trace.pins.map((p) => p.pinId));
|
|
13767
14188
|
const existing = this.tracesByPinPairKey.get(key);
|
|
13768
14189
|
if (existing) {
|
|
@@ -13782,11 +14203,43 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13782
14203
|
];
|
|
13783
14204
|
}
|
|
13784
14205
|
_step() {
|
|
13785
|
-
const
|
|
13786
|
-
if (
|
|
14206
|
+
const queuedConnection = this.queuedConnections.shift();
|
|
14207
|
+
if (queuedConnection) {
|
|
14208
|
+
if (queuedConnection.kind === "net_connection" && queuedConnection.connection.pinIds.length > 2) {
|
|
14209
|
+
const netConnections = [
|
|
14210
|
+
queuedConnection.connection,
|
|
14211
|
+
...this.queuedConnections.filter(
|
|
14212
|
+
(queued) => queued.kind === "net_connection" && queued.connection.pinIds.length > 2
|
|
14213
|
+
).map((queued) => queued.connection)
|
|
14214
|
+
];
|
|
14215
|
+
this.queuedConnections = this.queuedConnections.filter(
|
|
14216
|
+
(queued) => queued.kind !== "net_connection" || queued.connection.pinIds.length <= 2
|
|
14217
|
+
);
|
|
14218
|
+
for (const conversion of this.computeNetConnectionInlineConversions(
|
|
14219
|
+
netConnections
|
|
14220
|
+
)) {
|
|
14221
|
+
this.inlineNetLabelPlacements.push(...conversion.placements);
|
|
14222
|
+
const supersededTraceIds = this.supersededTraceIdsByGlobalConnNetId.get(
|
|
14223
|
+
conversion.globalConnNetId
|
|
14224
|
+
) ?? /* @__PURE__ */ new Set();
|
|
14225
|
+
for (const traceId of conversion.supersededTraceIds) {
|
|
14226
|
+
supersededTraceIds.add(traceId);
|
|
14227
|
+
}
|
|
14228
|
+
this.supersededTraceIdsByGlobalConnNetId.set(
|
|
14229
|
+
conversion.globalConnNetId,
|
|
14230
|
+
supersededTraceIds
|
|
14231
|
+
);
|
|
14232
|
+
}
|
|
14233
|
+
return;
|
|
14234
|
+
}
|
|
14235
|
+
const { connection } = queuedConnection;
|
|
13787
14236
|
const routedTraces = connection.pinIds.length === 2 ? this.tracesByPinPairKey.get(getPinPairKey2(connection.pinIds)) ?? [] : [];
|
|
13788
14237
|
if (routedTraces.length > 0) {
|
|
13789
|
-
const placement = this.computeInlinePlacement(
|
|
14238
|
+
const placement = this.computeInlinePlacement({
|
|
14239
|
+
connection,
|
|
14240
|
+
trace: routedTraces[0],
|
|
14241
|
+
pinIds: connection.pinIds
|
|
14242
|
+
});
|
|
13790
14243
|
if (placement) this.inlineNetLabelPlacements.push(placement);
|
|
13791
14244
|
} else {
|
|
13792
14245
|
const terminalPlacements = connection.pinIds.map(
|
|
@@ -13815,18 +14268,181 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13815
14268
|
this.solved = true;
|
|
13816
14269
|
this.stats.inlineNetLabelCount = this.inlineNetLabelPlacements.length;
|
|
13817
14270
|
}
|
|
14271
|
+
/**
|
|
14272
|
+
* Plans all opted-in multi-pin nets together. Short routed components can
|
|
14273
|
+
* mutually block the outward endpoint stubs that replace them, so tentative
|
|
14274
|
+
* replacements are ignored as obstacles only while their owning net still
|
|
14275
|
+
* converts successfully. Failed conversions retain both their traces and
|
|
14276
|
+
* their conventional labels, and the remaining conversions are retried.
|
|
14277
|
+
*/
|
|
14278
|
+
computeNetConnectionInlineConversions(connections) {
|
|
14279
|
+
const prospectiveTraceIdsByConnection = /* @__PURE__ */ new Map();
|
|
14280
|
+
for (const connection of connections) {
|
|
14281
|
+
const prospectiveTraceIds = /* @__PURE__ */ new Set();
|
|
14282
|
+
for (const component of this.getNetConnectionComponents(connection)) {
|
|
14283
|
+
if (component.traces.length === 0) continue;
|
|
14284
|
+
const hasInlinePlacement = component.traces.some(
|
|
14285
|
+
(trace) => Boolean(
|
|
14286
|
+
this.computeInlinePlacement({
|
|
14287
|
+
connection,
|
|
14288
|
+
trace,
|
|
14289
|
+
pinIds: component.pinIds
|
|
14290
|
+
})
|
|
14291
|
+
)
|
|
14292
|
+
);
|
|
14293
|
+
if (!hasInlinePlacement) {
|
|
14294
|
+
for (const trace of component.traces) {
|
|
14295
|
+
prospectiveTraceIds.add(trace.mspPairId);
|
|
14296
|
+
}
|
|
14297
|
+
}
|
|
14298
|
+
}
|
|
14299
|
+
prospectiveTraceIdsByConnection.set(connection, prospectiveTraceIds);
|
|
14300
|
+
}
|
|
14301
|
+
let ignoredTraceIds = new Set(
|
|
14302
|
+
[...prospectiveTraceIdsByConnection.values()].flatMap((ids) => [...ids])
|
|
14303
|
+
);
|
|
14304
|
+
while (true) {
|
|
14305
|
+
const conversions = connections.map((connection) => ({
|
|
14306
|
+
connection,
|
|
14307
|
+
conversion: this.computeNetConnectionInlinePlacements(
|
|
14308
|
+
connection,
|
|
14309
|
+
ignoredTraceIds,
|
|
14310
|
+
prospectiveTraceIdsByConnection.get(connection) ?? /* @__PURE__ */ new Set()
|
|
14311
|
+
)
|
|
14312
|
+
}));
|
|
14313
|
+
const nextIgnoredTraceIds = new Set(
|
|
14314
|
+
conversions.flatMap(
|
|
14315
|
+
({ conversion }) => conversion ? [...conversion.supersededTraceIds] : []
|
|
14316
|
+
)
|
|
14317
|
+
);
|
|
14318
|
+
if (setsEqual(ignoredTraceIds, nextIgnoredTraceIds)) {
|
|
14319
|
+
return conversions.flatMap(
|
|
14320
|
+
({ conversion }) => conversion ? [conversion] : []
|
|
14321
|
+
);
|
|
14322
|
+
}
|
|
14323
|
+
ignoredTraceIds = nextIgnoredTraceIds;
|
|
14324
|
+
}
|
|
14325
|
+
}
|
|
14326
|
+
/**
|
|
14327
|
+
* Splits an input net into the connected components created by its solved
|
|
14328
|
+
* traces. This intentionally does not depend on anchored-label placement:
|
|
14329
|
+
* a group whose anchored label failed still has the same routing topology.
|
|
14330
|
+
*/
|
|
14331
|
+
getNetConnectionComponents(connection) {
|
|
14332
|
+
const firstPinId = connection.pinIds[0];
|
|
14333
|
+
if (!firstPinId) return [];
|
|
14334
|
+
const canonicalGlobalConnNetId = this.globalConnMap.getNetConnectedToId(firstPinId);
|
|
14335
|
+
if (!canonicalGlobalConnNetId) return [];
|
|
14336
|
+
const inputPinIds = new Set(
|
|
14337
|
+
this.inputProblem.chips.flatMap(
|
|
14338
|
+
(chip) => chip.pins.map((pin) => pin.pinId)
|
|
14339
|
+
)
|
|
14340
|
+
);
|
|
14341
|
+
const pinIdsInGlobalNet = this.globalConnMap.getIdsConnectedToNet(
|
|
14342
|
+
canonicalGlobalConnNetId
|
|
14343
|
+
).filter((id) => inputPinIds.has(id));
|
|
14344
|
+
const labeledPinIds = new Set(connection.pinIds);
|
|
14345
|
+
return getTraceConnectedPinComponents({
|
|
14346
|
+
pinIds: pinIdsInGlobalNet,
|
|
14347
|
+
// Available-net-orientation traces only connect a pin to its generated
|
|
14348
|
+
// anchored label. They are removed when that label becomes inline, so
|
|
14349
|
+
// treating them as routed circuitry would leave text on a deleted wire.
|
|
14350
|
+
traces: this.traces.filter(
|
|
14351
|
+
(trace) => !isGeneratedAnchoredLabelConnector(trace)
|
|
14352
|
+
)
|
|
14353
|
+
}).map((component) => ({
|
|
14354
|
+
pinIds: component.pinIds,
|
|
14355
|
+
labeledPinIds: component.pinIds.filter(
|
|
14356
|
+
(pinId) => labeledPinIds.has(pinId)
|
|
14357
|
+
),
|
|
14358
|
+
traces: component.traces.sort(
|
|
14359
|
+
(a, b) => getTraceLength2(b) - getTraceLength2(a)
|
|
14360
|
+
)
|
|
14361
|
+
})).filter((component) => component.labeledPinIds.length > 0);
|
|
14362
|
+
}
|
|
14363
|
+
getGlobalConnNetId(connection) {
|
|
14364
|
+
const firstPinId = connection.pinIds[0];
|
|
14365
|
+
if (!firstPinId) return void 0;
|
|
14366
|
+
const connectionPinIds = new Set(connection.pinIds);
|
|
14367
|
+
return this.traces.find(
|
|
14368
|
+
(trace) => trace.pins.some((pin) => connectionPinIds.has(pin.pinId))
|
|
14369
|
+
)?.globalConnNetId ?? this.inputNetLabelPlacements.find(
|
|
14370
|
+
(placement) => placement.netId === connection.netId
|
|
14371
|
+
)?.globalConnNetId ?? this.globalConnMap.getNetConnectedToId(firstPinId) ?? void 0;
|
|
14372
|
+
}
|
|
14373
|
+
/**
|
|
14374
|
+
* Converts every conventional label representation for an opted-in named
|
|
14375
|
+
* net. Routed connected components become labels on their representative
|
|
14376
|
+
* trace; disconnected pins become outward terminal stubs. The conversion is
|
|
14377
|
+
* atomic so one blocked candidate cannot leave mixed label styles on a net.
|
|
14378
|
+
*/
|
|
14379
|
+
computeNetConnectionInlinePlacements(connection, ignoredTraceIds, forcedTerminalTraceIds) {
|
|
14380
|
+
const components = this.getNetConnectionComponents(connection);
|
|
14381
|
+
const globalConnNetId = this.getGlobalConnNetId(connection);
|
|
14382
|
+
if (!globalConnNetId) return null;
|
|
14383
|
+
const inlinePlacements = [];
|
|
14384
|
+
const supersededTraceIds = /* @__PURE__ */ new Set();
|
|
14385
|
+
for (const component of components) {
|
|
14386
|
+
const shouldUseTerminalStubs = component.traces.some(
|
|
14387
|
+
(trace) => forcedTerminalTraceIds.has(trace.mspPairId)
|
|
14388
|
+
);
|
|
14389
|
+
let inlinePlacement = null;
|
|
14390
|
+
if (!shouldUseTerminalStubs) {
|
|
14391
|
+
for (const trace of component.traces) {
|
|
14392
|
+
inlinePlacement = this.computeInlinePlacement({
|
|
14393
|
+
connection,
|
|
14394
|
+
trace,
|
|
14395
|
+
pinIds: component.pinIds,
|
|
14396
|
+
ignoredTraceIds
|
|
14397
|
+
});
|
|
14398
|
+
if (inlinePlacement) break;
|
|
14399
|
+
}
|
|
14400
|
+
}
|
|
14401
|
+
if (inlinePlacement) {
|
|
14402
|
+
inlinePlacements.push(inlinePlacement);
|
|
14403
|
+
continue;
|
|
14404
|
+
}
|
|
14405
|
+
if (component.traces.length > 0 && !shouldUseTerminalStubs) {
|
|
14406
|
+
return null;
|
|
14407
|
+
}
|
|
14408
|
+
if (component.labeledPinIds.length !== component.pinIds.length) {
|
|
14409
|
+
return null;
|
|
14410
|
+
}
|
|
14411
|
+
const terminalPlacements = component.pinIds.map(
|
|
14412
|
+
(pinId) => this.computeTerminalInlinePlacement(
|
|
14413
|
+
connection,
|
|
14414
|
+
pinId,
|
|
14415
|
+
globalConnNetId,
|
|
14416
|
+
ignoredTraceIds
|
|
14417
|
+
)
|
|
14418
|
+
);
|
|
14419
|
+
if (terminalPlacements.some((placement) => placement === null)) {
|
|
14420
|
+
return null;
|
|
14421
|
+
}
|
|
14422
|
+
inlinePlacements.push(
|
|
14423
|
+
...terminalPlacements.filter(
|
|
14424
|
+
(placement) => placement !== null
|
|
14425
|
+
)
|
|
14426
|
+
);
|
|
14427
|
+
for (const trace of component.traces) {
|
|
14428
|
+
supersededTraceIds.add(trace.mspPairId);
|
|
14429
|
+
}
|
|
14430
|
+
}
|
|
14431
|
+
return { globalConnNetId, placements: inlinePlacements, supersededTraceIds };
|
|
14432
|
+
}
|
|
13818
14433
|
/**
|
|
13819
14434
|
* Converts one conventional endpoint placement into an inline label on a
|
|
13820
14435
|
* generated outward stub. The stub follows the pin's true facing direction;
|
|
13821
14436
|
* an anchored label may finish in another direction after an elbow, which is
|
|
13822
14437
|
* not the direction a terminal stub should leave the pin.
|
|
13823
14438
|
*/
|
|
13824
|
-
computeTerminalInlinePlacement(connection, pinId) {
|
|
14439
|
+
computeTerminalInlinePlacement(connection, pinId, knownGlobalConnNetId, ignoredTraceIds = /* @__PURE__ */ new Set()) {
|
|
13825
14440
|
if (!connection.netId) return null;
|
|
13826
14441
|
const anchoredPlacement = this.inputNetLabelPlacements.find(
|
|
13827
14442
|
(placement) => placement.netId === connection.netId && placement.pinIds.length === 1 && placement.pinIds[0] === pinId
|
|
13828
14443
|
);
|
|
13829
|
-
|
|
14444
|
+
const globalConnNetId = knownGlobalConnNetId ?? anchoredPlacement?.globalConnNetId;
|
|
14445
|
+
if (!globalConnNetId) return null;
|
|
13830
14446
|
const inputChip = this.inputProblem.chips.find(
|
|
13831
14447
|
(chip) => chip.pins.some((pin) => pin.pinId === pinId)
|
|
13832
14448
|
);
|
|
@@ -13835,6 +14451,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13835
14451
|
const netLabelText = connection.netLabelText?.trim() || void 0;
|
|
13836
14452
|
const width = connection.inlineNetLabelWidth ?? connection.netLabelWidth ?? estimateInlineNetLabelWidth(netLabelText ?? connection.netId, height);
|
|
13837
14453
|
const stubLength = Math.max(width + 0.2, 0.6);
|
|
14454
|
+
if (!inputPin && !anchoredPlacement) return null;
|
|
13838
14455
|
const start = inputPin ? { x: inputPin.x, y: inputPin.y } : anchoredPlacement.anchorPoint;
|
|
13839
14456
|
const direction = inputPin && inputChip ? inputPin._facingDirection ?? getPinDirection(inputPin, inputChip) : anchoredPlacement.orientation;
|
|
13840
14457
|
const intendedEnd = direction === "x+" ? { x: start.x + stubLength, y: start.y } : direction === "x-" ? { x: start.x - stubLength, y: start.y } : direction === "y+" ? { x: start.x, y: start.y + stubLength } : { x: start.x, y: start.y - stubLength };
|
|
@@ -13843,53 +14460,60 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13843
14460
|
intendedEnd,
|
|
13844
14461
|
minimumLength: width + 2 * INLINE_NET_LABEL_TRACE_MARGIN,
|
|
13845
14462
|
traces: this.traces,
|
|
13846
|
-
ownGlobalConnNetId:
|
|
14463
|
+
ownGlobalConnNetId: globalConnNetId,
|
|
14464
|
+
ignoredTraceIds
|
|
13847
14465
|
});
|
|
13848
14466
|
if (!end) return null;
|
|
13849
14467
|
const axis = direction === "x+" || direction === "x-" ? "x" : "y";
|
|
13850
|
-
const side = axis === "x" ? "y+" : "x-";
|
|
13851
14468
|
const anchorPoint = {
|
|
13852
14469
|
x: (start.x + end.x) / 2,
|
|
13853
14470
|
y: (start.y + end.y) / 2
|
|
13854
14471
|
};
|
|
13855
14472
|
const offset = height / 2 + INLINE_NET_LABEL_TRACE_MARGIN;
|
|
13856
|
-
const
|
|
13857
|
-
const
|
|
13858
|
-
|
|
13859
|
-
|
|
13860
|
-
|
|
13861
|
-
|
|
13862
|
-
|
|
13863
|
-
|
|
13864
|
-
|
|
13865
|
-
|
|
13866
|
-
|
|
13867
|
-
|
|
13868
|
-
|
|
13869
|
-
|
|
13870
|
-
|
|
13871
|
-
|
|
13872
|
-
|
|
13873
|
-
|
|
14473
|
+
const sides = axis === "x" ? ["y+", "y-"] : ["x-", "x+"];
|
|
14474
|
+
for (const side of sides) {
|
|
14475
|
+
const center = side === "y+" ? { x: anchorPoint.x, y: anchorPoint.y + offset } : side === "y-" ? { x: anchorPoint.x, y: anchorPoint.y - offset } : side === "x-" ? { x: anchorPoint.x - offset, y: anchorPoint.y } : { x: anchorPoint.x + offset, y: anchorPoint.y };
|
|
14476
|
+
const halfAlong = width / 2;
|
|
14477
|
+
const halfAcross = height / 2;
|
|
14478
|
+
const bounds = axis === "x" ? {
|
|
14479
|
+
minX: center.x - halfAlong,
|
|
14480
|
+
maxX: center.x + halfAlong,
|
|
14481
|
+
minY: center.y - halfAcross,
|
|
14482
|
+
maxY: center.y + halfAcross
|
|
14483
|
+
} : {
|
|
14484
|
+
minX: center.x - halfAcross,
|
|
14485
|
+
maxX: center.x + halfAcross,
|
|
14486
|
+
minY: center.y - halfAlong,
|
|
14487
|
+
maxY: center.y + halfAlong
|
|
14488
|
+
};
|
|
14489
|
+
if (this.isObstructed(bounds, {
|
|
14490
|
+
ownGlobalConnNetId: globalConnNetId,
|
|
14491
|
+
ignoredTraceIds
|
|
14492
|
+
})) {
|
|
14493
|
+
continue;
|
|
14494
|
+
}
|
|
14495
|
+
return {
|
|
14496
|
+
globalConnNetId,
|
|
14497
|
+
netId: connection.netId,
|
|
14498
|
+
netLabelText,
|
|
14499
|
+
pinIds: [pinId],
|
|
14500
|
+
stubTracePath: [start, end],
|
|
14501
|
+
axis,
|
|
14502
|
+
anchorPoint,
|
|
14503
|
+
center,
|
|
14504
|
+
width,
|
|
14505
|
+
height,
|
|
14506
|
+
side
|
|
14507
|
+
};
|
|
13874
14508
|
}
|
|
13875
|
-
return
|
|
13876
|
-
globalConnNetId: anchoredPlacement.globalConnNetId,
|
|
13877
|
-
netId: connection.netId,
|
|
13878
|
-
netLabelText,
|
|
13879
|
-
pinIds: [pinId],
|
|
13880
|
-
stubTracePath: [start, end],
|
|
13881
|
-
axis,
|
|
13882
|
-
anchorPoint,
|
|
13883
|
-
center,
|
|
13884
|
-
width,
|
|
13885
|
-
height,
|
|
13886
|
-
side
|
|
13887
|
-
};
|
|
14509
|
+
return null;
|
|
13888
14510
|
}
|
|
13889
|
-
computeInlinePlacement(
|
|
13890
|
-
|
|
13891
|
-
|
|
13892
|
-
|
|
14511
|
+
computeInlinePlacement({
|
|
14512
|
+
connection,
|
|
14513
|
+
trace,
|
|
14514
|
+
pinIds,
|
|
14515
|
+
ignoredTraceIds = /* @__PURE__ */ new Set()
|
|
14516
|
+
}) {
|
|
13893
14517
|
const segments = getAxisAlignedSegments(trace.tracePath);
|
|
13894
14518
|
if (segments.length === 0) return null;
|
|
13895
14519
|
const height = connection.inlineNetLabelHeight ?? DEFAULT_INLINE_NET_LABEL_HEIGHT;
|
|
@@ -13917,7 +14541,8 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13917
14541
|
};
|
|
13918
14542
|
if (this.isObstructed(bounds, {
|
|
13919
14543
|
ownTrace: trace,
|
|
13920
|
-
ownGlobalConnNetId: trace.globalConnNetId
|
|
14544
|
+
ownGlobalConnNetId: trace.globalConnNetId,
|
|
14545
|
+
ignoredTraceIds
|
|
13921
14546
|
}))
|
|
13922
14547
|
continue;
|
|
13923
14548
|
return {
|
|
@@ -13925,7 +14550,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13925
14550
|
netId: connection.netId,
|
|
13926
14551
|
netLabelText,
|
|
13927
14552
|
mspPairId: trace.mspPairId,
|
|
13928
|
-
pinIds: [...
|
|
14553
|
+
pinIds: [...pinIds],
|
|
13929
14554
|
axis: segment.axis,
|
|
13930
14555
|
anchorPoint,
|
|
13931
14556
|
center,
|
|
@@ -13942,7 +14567,9 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13942
14567
|
netLabelText,
|
|
13943
14568
|
width,
|
|
13944
14569
|
height,
|
|
13945
|
-
offset
|
|
14570
|
+
offset,
|
|
14571
|
+
pinIds,
|
|
14572
|
+
ignoredTraceIds
|
|
13946
14573
|
});
|
|
13947
14574
|
if (spanPlacement) return spanPlacement;
|
|
13948
14575
|
return null;
|
|
@@ -13959,7 +14586,9 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13959
14586
|
netLabelText,
|
|
13960
14587
|
width,
|
|
13961
14588
|
height,
|
|
13962
|
-
offset
|
|
14589
|
+
offset,
|
|
14590
|
+
pinIds,
|
|
14591
|
+
ignoredTraceIds
|
|
13963
14592
|
}) {
|
|
13964
14593
|
const path = trace.tracePath;
|
|
13965
14594
|
if (path.length < 2) return null;
|
|
@@ -14009,7 +14638,8 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
14009
14638
|
};
|
|
14010
14639
|
if (this.isObstructed(bounds, {
|
|
14011
14640
|
ownTrace: trace,
|
|
14012
|
-
ownGlobalConnNetId: trace.globalConnNetId
|
|
14641
|
+
ownGlobalConnNetId: trace.globalConnNetId,
|
|
14642
|
+
ignoredTraceIds
|
|
14013
14643
|
}))
|
|
14014
14644
|
continue;
|
|
14015
14645
|
const anchorPoint = axis === "x" ? { x: along, y: side === "y+" ? maxY : minY } : { x: side === "x-" ? minX : maxX, y: along };
|
|
@@ -14018,7 +14648,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
14018
14648
|
netId: connection.netId,
|
|
14019
14649
|
netLabelText,
|
|
14020
14650
|
mspPairId: trace.mspPairId,
|
|
14021
|
-
pinIds: [...
|
|
14651
|
+
pinIds: [...pinIds],
|
|
14022
14652
|
axis,
|
|
14023
14653
|
anchorPoint,
|
|
14024
14654
|
center,
|
|
@@ -14036,7 +14666,8 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
14036
14666
|
*/
|
|
14037
14667
|
isObstructed(bounds, {
|
|
14038
14668
|
ownTrace,
|
|
14039
|
-
ownGlobalConnNetId
|
|
14669
|
+
ownGlobalConnNetId,
|
|
14670
|
+
ignoredTraceIds = /* @__PURE__ */ new Set()
|
|
14040
14671
|
}) {
|
|
14041
14672
|
for (const chip of this.inputProblem.chips) {
|
|
14042
14673
|
const chipBounds = {
|
|
@@ -14051,9 +14682,10 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
14051
14682
|
if (boundsOverlap(bounds, getTextBoxBounds(textBox))) return true;
|
|
14052
14683
|
}
|
|
14053
14684
|
for (const trace of this.traces) {
|
|
14685
|
+
if (ignoredTraceIds.has(trace.mspPairId)) continue;
|
|
14054
14686
|
if (ownTrace && trace.mspPairId === ownTrace.mspPairId) continue;
|
|
14055
14687
|
if (trace.globalConnNetId === ownGlobalConnNetId) continue;
|
|
14056
|
-
if (
|
|
14688
|
+
if (doesPathIntersectBounds3(trace.tracePath, bounds)) return true;
|
|
14057
14689
|
}
|
|
14058
14690
|
return false;
|
|
14059
14691
|
}
|
|
@@ -14061,36 +14693,94 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
14061
14693
|
* Net label placements superseded by an inline label. A net gets one label or
|
|
14062
14694
|
* the other, never both.
|
|
14063
14695
|
*/
|
|
14064
|
-
getSupersededNetLabelKeys() {
|
|
14696
|
+
getSupersededNetLabelKeys(placements = this.inlineNetLabelPlacements) {
|
|
14065
14697
|
const keys = /* @__PURE__ */ new Set();
|
|
14066
|
-
for (const placement of
|
|
14698
|
+
for (const placement of placements) {
|
|
14067
14699
|
keys.add(placement.globalConnNetId);
|
|
14068
14700
|
}
|
|
14069
14701
|
return keys;
|
|
14070
14702
|
}
|
|
14071
|
-
getOutputTraces(supersededNetLabelKeys) {
|
|
14703
|
+
getOutputTraces(supersededNetLabelKeys, supersededTraceIds) {
|
|
14072
14704
|
return this.traces.filter(
|
|
14073
|
-
(trace) => !(supersededNetLabelKeys.has(trace.globalConnNetId) && trace
|
|
14705
|
+
(trace) => !supersededTraceIds.has(trace.mspPairId) && !(supersededNetLabelKeys.has(trace.globalConnNetId) && isGeneratedAnchoredLabelConnector(trace))
|
|
14074
14706
|
);
|
|
14075
14707
|
}
|
|
14708
|
+
getInlineGlobalsOverlappingAnchoredLabels({
|
|
14709
|
+
inlineNetLabelPlacements,
|
|
14710
|
+
anchoredNetLabelPlacements
|
|
14711
|
+
}) {
|
|
14712
|
+
const blockedGlobalConnNetIds = /* @__PURE__ */ new Set();
|
|
14713
|
+
for (const inlinePlacement of inlineNetLabelPlacements) {
|
|
14714
|
+
const inlineBounds = getInlinePlacementBounds(inlinePlacement);
|
|
14715
|
+
for (const anchoredPlacement of anchoredNetLabelPlacements) {
|
|
14716
|
+
if (anchoredPlacement.globalConnNetId === inlinePlacement.globalConnNetId) {
|
|
14717
|
+
continue;
|
|
14718
|
+
}
|
|
14719
|
+
const anchoredBounds = getAnchoredPlacementBounds(anchoredPlacement);
|
|
14720
|
+
if (boundsOverlap(inlineBounds, anchoredBounds) || inlinePlacement.stubTracePath && doesPathIntersectBounds3(
|
|
14721
|
+
inlinePlacement.stubTracePath,
|
|
14722
|
+
anchoredBounds
|
|
14723
|
+
)) {
|
|
14724
|
+
blockedGlobalConnNetIds.add(inlinePlacement.globalConnNetId);
|
|
14725
|
+
break;
|
|
14726
|
+
}
|
|
14727
|
+
}
|
|
14728
|
+
}
|
|
14729
|
+
return blockedGlobalConnNetIds;
|
|
14730
|
+
}
|
|
14076
14731
|
buildPostProcessedOutput() {
|
|
14077
|
-
|
|
14078
|
-
|
|
14079
|
-
|
|
14080
|
-
|
|
14081
|
-
|
|
14082
|
-
|
|
14083
|
-
|
|
14084
|
-
|
|
14085
|
-
|
|
14086
|
-
|
|
14087
|
-
|
|
14088
|
-
|
|
14089
|
-
|
|
14090
|
-
|
|
14091
|
-
|
|
14092
|
-
|
|
14093
|
-
|
|
14732
|
+
let activeInlinePlacements = this.inlineNetLabelPlacements;
|
|
14733
|
+
while (true) {
|
|
14734
|
+
const supersededNetLabelKeys = this.getSupersededNetLabelKeys(
|
|
14735
|
+
activeInlinePlacements
|
|
14736
|
+
);
|
|
14737
|
+
const supersededTraceIds = new Set(
|
|
14738
|
+
[...supersededNetLabelKeys].flatMap((globalConnNetId) => [
|
|
14739
|
+
...this.supersededTraceIdsByGlobalConnNetId.get(globalConnNetId) ?? []
|
|
14740
|
+
])
|
|
14741
|
+
);
|
|
14742
|
+
const retainedNetLabelPlacements = this.inputNetLabelPlacements.filter(
|
|
14743
|
+
(placement) => !supersededNetLabelKeys.has(placement.globalConnNetId)
|
|
14744
|
+
);
|
|
14745
|
+
const outputTraces = this.getOutputTraces(
|
|
14746
|
+
supersededNetLabelKeys,
|
|
14747
|
+
supersededTraceIds
|
|
14748
|
+
);
|
|
14749
|
+
const pushed = pushAnchoredNetLabelsAwayFromInlineLabels({
|
|
14750
|
+
inputProblem: this.inputProblem,
|
|
14751
|
+
traces: outputTraces,
|
|
14752
|
+
netLabelPlacements: retainedNetLabelPlacements,
|
|
14753
|
+
inlineNetLabelPlacements: activeInlinePlacements
|
|
14754
|
+
});
|
|
14755
|
+
const blockedGlobalConnNetIds = this.getInlineGlobalsOverlappingAnchoredLabels({
|
|
14756
|
+
inlineNetLabelPlacements: activeInlinePlacements,
|
|
14757
|
+
anchoredNetLabelPlacements: pushed.netLabelPlacements
|
|
14758
|
+
});
|
|
14759
|
+
if (blockedGlobalConnNetIds.size > 0) {
|
|
14760
|
+
const shiftedInlineTerminalLabels = pushInlineTerminalLabelsAwayFromAnchoredLabels({
|
|
14761
|
+
inputProblem: this.inputProblem,
|
|
14762
|
+
traces: pushed.traces,
|
|
14763
|
+
anchoredNetLabelPlacements: pushed.netLabelPlacements,
|
|
14764
|
+
inlineNetLabelPlacements: activeInlinePlacements
|
|
14765
|
+
});
|
|
14766
|
+
if (shiftedInlineTerminalLabels.movedGroupCount > 0) {
|
|
14767
|
+
activeInlinePlacements = shiftedInlineTerminalLabels.inlineNetLabelPlacements;
|
|
14768
|
+
continue;
|
|
14769
|
+
}
|
|
14770
|
+
}
|
|
14771
|
+
if (blockedGlobalConnNetIds.size === 0) {
|
|
14772
|
+
this.inlineNetLabelPlacements = activeInlinePlacements;
|
|
14773
|
+
this.stats.pushedAnchoredNetLabelCount = pushed.movedLabelCount;
|
|
14774
|
+
return {
|
|
14775
|
+
traces: pushed.traces,
|
|
14776
|
+
netLabelPlacements: pushed.netLabelPlacements,
|
|
14777
|
+
inlineNetLabelPlacements: activeInlinePlacements
|
|
14778
|
+
};
|
|
14779
|
+
}
|
|
14780
|
+
activeInlinePlacements = activeInlinePlacements.filter(
|
|
14781
|
+
(placement) => !blockedGlobalConnNetIds.has(placement.globalConnNetId)
|
|
14782
|
+
);
|
|
14783
|
+
}
|
|
14094
14784
|
}
|
|
14095
14785
|
getOutput() {
|
|
14096
14786
|
if (this.postProcessedOutput) return this.postProcessedOutput;
|
|
@@ -14225,7 +14915,7 @@ var getAnchorCandidates = (segment, labelWidth, step = 0.1) => {
|
|
|
14225
14915
|
offsets.push(slack / 2, -slack / 2);
|
|
14226
14916
|
return offsets.map((offset) => pointAt(mid + offset * direction));
|
|
14227
14917
|
};
|
|
14228
|
-
var
|
|
14918
|
+
var doesPathIntersectBounds3 = (path, bounds) => {
|
|
14229
14919
|
for (let i = 0; i < path.length - 1; i++) {
|
|
14230
14920
|
const a = path[i];
|
|
14231
14921
|
const b = path[i + 1];
|
|
@@ -14245,7 +14935,8 @@ var getCollisionLimitedTerminalStubEnd = ({
|
|
|
14245
14935
|
intendedEnd,
|
|
14246
14936
|
minimumLength,
|
|
14247
14937
|
traces,
|
|
14248
|
-
ownGlobalConnNetId
|
|
14938
|
+
ownGlobalConnNetId,
|
|
14939
|
+
ignoredTraceIds
|
|
14249
14940
|
}) => {
|
|
14250
14941
|
const isHorizontal4 = Math.abs(intendedEnd.x - start.x) >= Math.abs(intendedEnd.y - start.y);
|
|
14251
14942
|
const alongAxis = isHorizontal4 ? "x" : "y";
|
|
@@ -14254,6 +14945,7 @@ var getCollisionLimitedTerminalStubEnd = ({
|
|
|
14254
14945
|
const intendedLength = Math.abs(intendedEnd[alongAxis] - start[alongAxis]);
|
|
14255
14946
|
let availableLength = intendedLength;
|
|
14256
14947
|
for (const trace of traces) {
|
|
14948
|
+
if (ignoredTraceIds.has(trace.mspPairId)) continue;
|
|
14257
14949
|
if (trace.globalConnNetId === ownGlobalConnNetId) continue;
|
|
14258
14950
|
for (let segmentIndex = 0; segmentIndex < trace.tracePath.length - 1; segmentIndex++) {
|
|
14259
14951
|
const segmentStart = trace.tracePath[segmentIndex];
|