@tscircuit/schematic-trace-solver 0.0.159 → 0.0.160
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 +40 -9
- package/dist/index.js +636 -107
- 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/types/InputProblem.ts +5 -4
- package/package.json +1 -1
- 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/repros/repro-usb-power-vbus-label-detour.test.ts +14 -0
- 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) => {
|
|
@@ -13695,7 +13716,7 @@ var pushAnchoredNetLabelsAwayFromInlineLabels = ({
|
|
|
13695
13716
|
const connectorObstructed = inlineBounds.some(
|
|
13696
13717
|
(bounds) => pathIntersectsBounds(connector.tracePath, bounds)
|
|
13697
13718
|
) || inputProblem.chips.some(
|
|
13698
|
-
(chip) => pathIntersectsBounds(connector.tracePath, {
|
|
13719
|
+
(chip) => !ownerChipIds.has(chip.chipId) && pathIntersectsBounds(connector.tracePath, {
|
|
13699
13720
|
minX: chip.center.x - chip.width / 2,
|
|
13700
13721
|
maxX: chip.center.x + chip.width / 2,
|
|
13701
13722
|
minY: chip.center.y - chip.height / 2,
|
|
@@ -13732,20 +13753,247 @@ var pushAnchoredNetLabelsAwayFromInlineLabels = ({
|
|
|
13732
13753
|
};
|
|
13733
13754
|
};
|
|
13734
13755
|
|
|
13756
|
+
// lib/solvers/InlineNetLabelSolver/pushInlineTerminalLabelsAwayFromAnchoredLabels.ts
|
|
13757
|
+
var LABEL_CLEARANCE3 = 0.05;
|
|
13758
|
+
var MAX_OUTWARD_DISTANCE2 = 5;
|
|
13759
|
+
var getStubDirection2 = (path) => {
|
|
13760
|
+
const [start, end] = path;
|
|
13761
|
+
if (Math.abs(end.x - start.x) >= Math.abs(end.y - start.y)) {
|
|
13762
|
+
return end.x >= start.x ? "x+" : "x-";
|
|
13763
|
+
}
|
|
13764
|
+
return end.y >= start.y ? "y+" : "y-";
|
|
13765
|
+
};
|
|
13766
|
+
var getLabelBounds3 = (placement) => {
|
|
13767
|
+
const renderedWidth = placement.axis === "y" ? placement.height : placement.width;
|
|
13768
|
+
const renderedHeight = placement.axis === "y" ? placement.width : placement.height;
|
|
13769
|
+
return {
|
|
13770
|
+
minX: placement.center.x - renderedWidth / 2,
|
|
13771
|
+
maxX: placement.center.x + renderedWidth / 2,
|
|
13772
|
+
minY: placement.center.y - renderedHeight / 2,
|
|
13773
|
+
maxY: placement.center.y + renderedHeight / 2
|
|
13774
|
+
};
|
|
13775
|
+
};
|
|
13776
|
+
var getPathBounds2 = (path) => ({
|
|
13777
|
+
minX: Math.min(...path.map((point) => point.x)),
|
|
13778
|
+
maxX: Math.max(...path.map((point) => point.x)),
|
|
13779
|
+
minY: Math.min(...path.map((point) => point.y)),
|
|
13780
|
+
maxY: Math.max(...path.map((point) => point.y))
|
|
13781
|
+
});
|
|
13782
|
+
var doesPathIntersectBounds2 = (path, bounds) => {
|
|
13783
|
+
for (let index = 0; index < path.length - 1; index++) {
|
|
13784
|
+
if (boundsOverlap(getPathBounds2([path[index], path[index + 1]]), bounds)) {
|
|
13785
|
+
return true;
|
|
13786
|
+
}
|
|
13787
|
+
}
|
|
13788
|
+
return false;
|
|
13789
|
+
};
|
|
13790
|
+
var shiftPoint = (point, direction, distance7) => {
|
|
13791
|
+
switch (direction) {
|
|
13792
|
+
case "x+":
|
|
13793
|
+
return { x: point.x + distance7, y: point.y };
|
|
13794
|
+
case "x-":
|
|
13795
|
+
return { x: point.x - distance7, y: point.y };
|
|
13796
|
+
case "y+":
|
|
13797
|
+
return { x: point.x, y: point.y + distance7 };
|
|
13798
|
+
case "y-":
|
|
13799
|
+
return { x: point.x, y: point.y - distance7 };
|
|
13800
|
+
}
|
|
13801
|
+
};
|
|
13802
|
+
var shiftTerminalPlacement = (placement, direction, distance7) => {
|
|
13803
|
+
const [start, end] = placement.stubTracePath;
|
|
13804
|
+
const shiftedEnd = shiftPoint(end, direction, distance7);
|
|
13805
|
+
return {
|
|
13806
|
+
...placement,
|
|
13807
|
+
stubTracePath: [start, shiftedEnd],
|
|
13808
|
+
anchorPoint: shiftPoint(placement.anchorPoint, direction, distance7),
|
|
13809
|
+
center: shiftPoint(placement.center, direction, distance7)
|
|
13810
|
+
};
|
|
13811
|
+
};
|
|
13812
|
+
var getRequiredOutwardDistance2 = (movingBounds, obstacleBounds, direction) => {
|
|
13813
|
+
switch (direction) {
|
|
13814
|
+
case "x+":
|
|
13815
|
+
return obstacleBounds.maxX - movingBounds.minX + LABEL_CLEARANCE3;
|
|
13816
|
+
case "x-":
|
|
13817
|
+
return movingBounds.maxX - obstacleBounds.minX + LABEL_CLEARANCE3;
|
|
13818
|
+
case "y+":
|
|
13819
|
+
return obstacleBounds.maxY - movingBounds.minY + LABEL_CLEARANCE3;
|
|
13820
|
+
case "y-":
|
|
13821
|
+
return movingBounds.maxY - obstacleBounds.minY + LABEL_CLEARANCE3;
|
|
13822
|
+
}
|
|
13823
|
+
};
|
|
13824
|
+
var pushInlineTerminalLabelsAwayFromAnchoredLabels = ({
|
|
13825
|
+
inputProblem,
|
|
13826
|
+
traces,
|
|
13827
|
+
anchoredNetLabelPlacements,
|
|
13828
|
+
inlineNetLabelPlacements
|
|
13829
|
+
}) => {
|
|
13830
|
+
const chipIdByPinId = /* @__PURE__ */ new Map();
|
|
13831
|
+
for (const chip of inputProblem.chips) {
|
|
13832
|
+
for (const pin of chip.pins) chipIdByPinId.set(pin.pinId, chip.chipId);
|
|
13833
|
+
}
|
|
13834
|
+
const groups = /* @__PURE__ */ new Map();
|
|
13835
|
+
for (const [
|
|
13836
|
+
placementIndex,
|
|
13837
|
+
placement
|
|
13838
|
+
] of inlineNetLabelPlacements.entries()) {
|
|
13839
|
+
if (!placement.stubTracePath || placement.pinIds.length !== 1) continue;
|
|
13840
|
+
const direction = getStubDirection2(placement.stubTracePath);
|
|
13841
|
+
const ownerChipId = chipIdByPinId.get(placement.pinIds[0]);
|
|
13842
|
+
const groupKey = `${ownerChipId ?? placement.pinIds[0]}::${direction}`;
|
|
13843
|
+
const group = groups.get(groupKey) ?? [];
|
|
13844
|
+
group.push({ placementIndex, placement, direction, ownerChipId });
|
|
13845
|
+
groups.set(groupKey, group);
|
|
13846
|
+
}
|
|
13847
|
+
const outputPlacements = [...inlineNetLabelPlacements];
|
|
13848
|
+
let movedGroupCount = 0;
|
|
13849
|
+
for (const group of groups.values()) {
|
|
13850
|
+
const groupPlacementIndices = new Set(
|
|
13851
|
+
group.map(({ placementIndex }) => placementIndex)
|
|
13852
|
+
);
|
|
13853
|
+
const fixedInlinePlacements = outputPlacements.filter(
|
|
13854
|
+
(_, placementIndex) => !groupPlacementIndices.has(placementIndex)
|
|
13855
|
+
);
|
|
13856
|
+
const direction = group[0].direction;
|
|
13857
|
+
let distance7 = 0;
|
|
13858
|
+
for (let iteration = 0; iteration <= anchoredNetLabelPlacements.length; iteration++) {
|
|
13859
|
+
let requiredAdditionalDistance = 0;
|
|
13860
|
+
for (const { placement } of group) {
|
|
13861
|
+
const shiftedPlacement = shiftTerminalPlacement(
|
|
13862
|
+
placement,
|
|
13863
|
+
direction,
|
|
13864
|
+
distance7
|
|
13865
|
+
);
|
|
13866
|
+
const shiftedBounds = getLabelBounds3(shiftedPlacement);
|
|
13867
|
+
for (const anchoredPlacement of anchoredNetLabelPlacements) {
|
|
13868
|
+
if (anchoredPlacement.globalConnNetId === placement.globalConnNetId) {
|
|
13869
|
+
continue;
|
|
13870
|
+
}
|
|
13871
|
+
const anchoredBounds = getLabelBounds3(anchoredPlacement);
|
|
13872
|
+
if (!boundsOverlap(shiftedBounds, anchoredBounds)) continue;
|
|
13873
|
+
requiredAdditionalDistance = Math.max(
|
|
13874
|
+
requiredAdditionalDistance,
|
|
13875
|
+
getRequiredOutwardDistance2(
|
|
13876
|
+
shiftedBounds,
|
|
13877
|
+
anchoredBounds,
|
|
13878
|
+
direction
|
|
13879
|
+
)
|
|
13880
|
+
);
|
|
13881
|
+
}
|
|
13882
|
+
}
|
|
13883
|
+
if (requiredAdditionalDistance <= 0) break;
|
|
13884
|
+
distance7 += requiredAdditionalDistance;
|
|
13885
|
+
}
|
|
13886
|
+
if (distance7 <= 0 || distance7 > MAX_OUTWARD_DISTANCE2) continue;
|
|
13887
|
+
const proposals = group.map(
|
|
13888
|
+
({ placement }) => shiftTerminalPlacement(placement, direction, distance7)
|
|
13889
|
+
);
|
|
13890
|
+
const hasConflict = proposals.some((proposal, proposalIndex) => {
|
|
13891
|
+
const originalPlacement = group[proposalIndex].placement;
|
|
13892
|
+
const originalEnd = originalPlacement.stubTracePath[1];
|
|
13893
|
+
const shiftedEnd = proposal.stubTracePath[1];
|
|
13894
|
+
const addedStubSegment = [originalEnd, shiftedEnd];
|
|
13895
|
+
const labelBounds = getLabelBounds3(proposal);
|
|
13896
|
+
const ownerChipId = group[proposalIndex].ownerChipId;
|
|
13897
|
+
if (anchoredNetLabelPlacements.some((anchoredPlacement) => {
|
|
13898
|
+
if (anchoredPlacement.globalConnNetId === proposal.globalConnNetId) {
|
|
13899
|
+
return false;
|
|
13900
|
+
}
|
|
13901
|
+
const anchoredBounds = getLabelBounds3(anchoredPlacement);
|
|
13902
|
+
return boundsOverlap(labelBounds, anchoredBounds) || doesPathIntersectBounds2(addedStubSegment, anchoredBounds);
|
|
13903
|
+
})) {
|
|
13904
|
+
return true;
|
|
13905
|
+
}
|
|
13906
|
+
for (const chip of inputProblem.chips) {
|
|
13907
|
+
if (chip.chipId === ownerChipId) continue;
|
|
13908
|
+
const chipBounds = {
|
|
13909
|
+
minX: chip.center.x - chip.width / 2,
|
|
13910
|
+
maxX: chip.center.x + chip.width / 2,
|
|
13911
|
+
minY: chip.center.y - chip.height / 2,
|
|
13912
|
+
maxY: chip.center.y + chip.height / 2
|
|
13913
|
+
};
|
|
13914
|
+
if (boundsOverlap(labelBounds, chipBounds) || doesPathIntersectBounds2(addedStubSegment, chipBounds)) {
|
|
13915
|
+
return true;
|
|
13916
|
+
}
|
|
13917
|
+
}
|
|
13918
|
+
for (const textBox of inputProblem.textBoxes ?? []) {
|
|
13919
|
+
const textBounds = getTextBoxBounds(textBox);
|
|
13920
|
+
if (boundsOverlap(labelBounds, textBounds) || doesPathIntersectBounds2(addedStubSegment, textBounds)) {
|
|
13921
|
+
return true;
|
|
13922
|
+
}
|
|
13923
|
+
}
|
|
13924
|
+
for (const trace of traces) {
|
|
13925
|
+
if (trace.globalConnNetId === proposal.globalConnNetId) continue;
|
|
13926
|
+
if (doesPathIntersectBounds2(trace.tracePath, labelBounds) || doesPathIntersectBounds2(
|
|
13927
|
+
trace.tracePath,
|
|
13928
|
+
getPathBounds2(addedStubSegment)
|
|
13929
|
+
)) {
|
|
13930
|
+
return true;
|
|
13931
|
+
}
|
|
13932
|
+
}
|
|
13933
|
+
for (const fixedPlacement of fixedInlinePlacements) {
|
|
13934
|
+
const fixedBounds = getLabelBounds3(fixedPlacement);
|
|
13935
|
+
if (boundsOverlap(labelBounds, fixedBounds) || doesPathIntersectBounds2(addedStubSegment, fixedBounds) || fixedPlacement.stubTracePath && doesPathIntersectBounds2(fixedPlacement.stubTracePath, labelBounds)) {
|
|
13936
|
+
return true;
|
|
13937
|
+
}
|
|
13938
|
+
}
|
|
13939
|
+
return false;
|
|
13940
|
+
});
|
|
13941
|
+
if (hasConflict) continue;
|
|
13942
|
+
for (const [groupIndex, { placementIndex }] of group.entries()) {
|
|
13943
|
+
outputPlacements[placementIndex] = proposals[groupIndex];
|
|
13944
|
+
}
|
|
13945
|
+
movedGroupCount++;
|
|
13946
|
+
}
|
|
13947
|
+
return {
|
|
13948
|
+
inlineNetLabelPlacements: outputPlacements,
|
|
13949
|
+
movedGroupCount
|
|
13950
|
+
};
|
|
13951
|
+
};
|
|
13952
|
+
|
|
13735
13953
|
// lib/solvers/InlineNetLabelSolver/InlineNetLabelSolver.ts
|
|
13736
13954
|
var DEFAULT_INLINE_NET_LABEL_HEIGHT = 0.18;
|
|
13737
13955
|
var INLINE_NET_LABEL_TRACE_MARGIN = 0.05;
|
|
13738
13956
|
var INLINE_NET_LABEL_STUB_TRACE_CLEARANCE = 0.05;
|
|
13739
13957
|
var INLINE_NET_LABEL_MAX_SPAN_JOG = 0.4;
|
|
13958
|
+
var AVAILABLE_NET_ORIENTATION_TRACE_PREFIX = "available-net-orientation-";
|
|
13959
|
+
var isGeneratedAnchoredLabelConnector = (trace) => trace.mspPairId.startsWith(AVAILABLE_NET_ORIENTATION_TRACE_PREFIX);
|
|
13740
13960
|
var getPinPairKey2 = (pinIds) => [...pinIds].sort().join("::");
|
|
13961
|
+
var getTraceLength2 = (trace) => {
|
|
13962
|
+
let length = 0;
|
|
13963
|
+
for (let index = 0; index < trace.tracePath.length - 1; index++) {
|
|
13964
|
+
const start = trace.tracePath[index];
|
|
13965
|
+
const end = trace.tracePath[index + 1];
|
|
13966
|
+
length += Math.abs(end.x - start.x) + Math.abs(end.y - start.y);
|
|
13967
|
+
}
|
|
13968
|
+
return length;
|
|
13969
|
+
};
|
|
13970
|
+
var setsEqual = (first, second) => first.size === second.size && [...first].every((value) => second.has(value));
|
|
13971
|
+
var getInlinePlacementBounds = (placement) => {
|
|
13972
|
+
const renderedWidth = placement.axis === "y" ? placement.height : placement.width;
|
|
13973
|
+
const renderedHeight = placement.axis === "y" ? placement.width : placement.height;
|
|
13974
|
+
return {
|
|
13975
|
+
minX: placement.center.x - renderedWidth / 2,
|
|
13976
|
+
maxX: placement.center.x + renderedWidth / 2,
|
|
13977
|
+
minY: placement.center.y - renderedHeight / 2,
|
|
13978
|
+
maxY: placement.center.y + renderedHeight / 2
|
|
13979
|
+
};
|
|
13980
|
+
};
|
|
13981
|
+
var getAnchoredPlacementBounds = (placement) => ({
|
|
13982
|
+
minX: placement.center.x - placement.width / 2,
|
|
13983
|
+
maxX: placement.center.x + placement.width / 2,
|
|
13984
|
+
minY: placement.center.y - placement.height / 2,
|
|
13985
|
+
maxY: placement.center.y + placement.height / 2
|
|
13986
|
+
});
|
|
13741
13987
|
var InlineNetLabelSolver = class extends BaseSolver {
|
|
13742
13988
|
inputProblem;
|
|
13743
13989
|
traces;
|
|
13744
13990
|
inputNetLabelPlacements;
|
|
13745
13991
|
inlineNetLabelPlacements = [];
|
|
13746
|
-
/** Eligible
|
|
13992
|
+
/** Eligible connections still waiting to be processed. */
|
|
13747
13993
|
queuedConnections;
|
|
13748
13994
|
tracesByPinPairKey;
|
|
13995
|
+
globalConnMap;
|
|
13996
|
+
supersededTraceIdsByGlobalConnNetId = /* @__PURE__ */ new Map();
|
|
13749
13997
|
hasAlignedPortOnlyStubs = false;
|
|
13750
13998
|
postProcessedOutput;
|
|
13751
13999
|
constructor(input) {
|
|
@@ -13753,16 +14001,26 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13753
14001
|
this.inputProblem = input.inputProblem;
|
|
13754
14002
|
this.traces = input.traces;
|
|
13755
14003
|
this.inputNetLabelPlacements = input.netLabelPlacements;
|
|
14004
|
+
this.globalConnMap = getConnectivityMapsFromInputProblem(
|
|
14005
|
+
this.inputProblem
|
|
14006
|
+
).netConnMap;
|
|
13756
14007
|
this.queuedConnections = [
|
|
13757
14008
|
...this.inputProblem.directConnections.filter(
|
|
13758
14009
|
(connection) => connection.allowInlineNetLabel && connection.netId
|
|
13759
|
-
)
|
|
14010
|
+
).map((connection) => ({
|
|
14011
|
+
kind: "direct_connection",
|
|
14012
|
+
connection
|
|
14013
|
+
})),
|
|
13760
14014
|
...this.inputProblem.netConnections.filter(
|
|
13761
|
-
(connection) => connection.allowInlineNetLabel && connection.pinIds.length >= 1 && connection.
|
|
13762
|
-
)
|
|
14015
|
+
(connection) => connection.allowInlineNetLabel && connection.pinIds.length >= 1 && connection.netId
|
|
14016
|
+
).map((connection) => ({
|
|
14017
|
+
kind: "net_connection",
|
|
14018
|
+
connection
|
|
14019
|
+
}))
|
|
13763
14020
|
];
|
|
13764
14021
|
this.tracesByPinPairKey = /* @__PURE__ */ new Map();
|
|
13765
14022
|
for (const trace of this.traces) {
|
|
14023
|
+
if (isGeneratedAnchoredLabelConnector(trace)) continue;
|
|
13766
14024
|
const key = getPinPairKey2(trace.pins.map((p) => p.pinId));
|
|
13767
14025
|
const existing = this.tracesByPinPairKey.get(key);
|
|
13768
14026
|
if (existing) {
|
|
@@ -13782,11 +14040,43 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13782
14040
|
];
|
|
13783
14041
|
}
|
|
13784
14042
|
_step() {
|
|
13785
|
-
const
|
|
13786
|
-
if (
|
|
14043
|
+
const queuedConnection = this.queuedConnections.shift();
|
|
14044
|
+
if (queuedConnection) {
|
|
14045
|
+
if (queuedConnection.kind === "net_connection" && queuedConnection.connection.pinIds.length > 2) {
|
|
14046
|
+
const netConnections = [
|
|
14047
|
+
queuedConnection.connection,
|
|
14048
|
+
...this.queuedConnections.filter(
|
|
14049
|
+
(queued) => queued.kind === "net_connection" && queued.connection.pinIds.length > 2
|
|
14050
|
+
).map((queued) => queued.connection)
|
|
14051
|
+
];
|
|
14052
|
+
this.queuedConnections = this.queuedConnections.filter(
|
|
14053
|
+
(queued) => queued.kind !== "net_connection" || queued.connection.pinIds.length <= 2
|
|
14054
|
+
);
|
|
14055
|
+
for (const conversion of this.computeNetConnectionInlineConversions(
|
|
14056
|
+
netConnections
|
|
14057
|
+
)) {
|
|
14058
|
+
this.inlineNetLabelPlacements.push(...conversion.placements);
|
|
14059
|
+
const supersededTraceIds = this.supersededTraceIdsByGlobalConnNetId.get(
|
|
14060
|
+
conversion.globalConnNetId
|
|
14061
|
+
) ?? /* @__PURE__ */ new Set();
|
|
14062
|
+
for (const traceId of conversion.supersededTraceIds) {
|
|
14063
|
+
supersededTraceIds.add(traceId);
|
|
14064
|
+
}
|
|
14065
|
+
this.supersededTraceIdsByGlobalConnNetId.set(
|
|
14066
|
+
conversion.globalConnNetId,
|
|
14067
|
+
supersededTraceIds
|
|
14068
|
+
);
|
|
14069
|
+
}
|
|
14070
|
+
return;
|
|
14071
|
+
}
|
|
14072
|
+
const { connection } = queuedConnection;
|
|
13787
14073
|
const routedTraces = connection.pinIds.length === 2 ? this.tracesByPinPairKey.get(getPinPairKey2(connection.pinIds)) ?? [] : [];
|
|
13788
14074
|
if (routedTraces.length > 0) {
|
|
13789
|
-
const placement = this.computeInlinePlacement(
|
|
14075
|
+
const placement = this.computeInlinePlacement({
|
|
14076
|
+
connection,
|
|
14077
|
+
trace: routedTraces[0],
|
|
14078
|
+
pinIds: connection.pinIds
|
|
14079
|
+
});
|
|
13790
14080
|
if (placement) this.inlineNetLabelPlacements.push(placement);
|
|
13791
14081
|
} else {
|
|
13792
14082
|
const terminalPlacements = connection.pinIds.map(
|
|
@@ -13815,18 +14105,181 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13815
14105
|
this.solved = true;
|
|
13816
14106
|
this.stats.inlineNetLabelCount = this.inlineNetLabelPlacements.length;
|
|
13817
14107
|
}
|
|
14108
|
+
/**
|
|
14109
|
+
* Plans all opted-in multi-pin nets together. Short routed components can
|
|
14110
|
+
* mutually block the outward endpoint stubs that replace them, so tentative
|
|
14111
|
+
* replacements are ignored as obstacles only while their owning net still
|
|
14112
|
+
* converts successfully. Failed conversions retain both their traces and
|
|
14113
|
+
* their conventional labels, and the remaining conversions are retried.
|
|
14114
|
+
*/
|
|
14115
|
+
computeNetConnectionInlineConversions(connections) {
|
|
14116
|
+
const prospectiveTraceIdsByConnection = /* @__PURE__ */ new Map();
|
|
14117
|
+
for (const connection of connections) {
|
|
14118
|
+
const prospectiveTraceIds = /* @__PURE__ */ new Set();
|
|
14119
|
+
for (const component of this.getNetConnectionComponents(connection)) {
|
|
14120
|
+
if (component.traces.length === 0) continue;
|
|
14121
|
+
const hasInlinePlacement = component.traces.some(
|
|
14122
|
+
(trace) => Boolean(
|
|
14123
|
+
this.computeInlinePlacement({
|
|
14124
|
+
connection,
|
|
14125
|
+
trace,
|
|
14126
|
+
pinIds: component.pinIds
|
|
14127
|
+
})
|
|
14128
|
+
)
|
|
14129
|
+
);
|
|
14130
|
+
if (!hasInlinePlacement) {
|
|
14131
|
+
for (const trace of component.traces) {
|
|
14132
|
+
prospectiveTraceIds.add(trace.mspPairId);
|
|
14133
|
+
}
|
|
14134
|
+
}
|
|
14135
|
+
}
|
|
14136
|
+
prospectiveTraceIdsByConnection.set(connection, prospectiveTraceIds);
|
|
14137
|
+
}
|
|
14138
|
+
let ignoredTraceIds = new Set(
|
|
14139
|
+
[...prospectiveTraceIdsByConnection.values()].flatMap((ids) => [...ids])
|
|
14140
|
+
);
|
|
14141
|
+
while (true) {
|
|
14142
|
+
const conversions = connections.map((connection) => ({
|
|
14143
|
+
connection,
|
|
14144
|
+
conversion: this.computeNetConnectionInlinePlacements(
|
|
14145
|
+
connection,
|
|
14146
|
+
ignoredTraceIds,
|
|
14147
|
+
prospectiveTraceIdsByConnection.get(connection) ?? /* @__PURE__ */ new Set()
|
|
14148
|
+
)
|
|
14149
|
+
}));
|
|
14150
|
+
const nextIgnoredTraceIds = new Set(
|
|
14151
|
+
conversions.flatMap(
|
|
14152
|
+
({ conversion }) => conversion ? [...conversion.supersededTraceIds] : []
|
|
14153
|
+
)
|
|
14154
|
+
);
|
|
14155
|
+
if (setsEqual(ignoredTraceIds, nextIgnoredTraceIds)) {
|
|
14156
|
+
return conversions.flatMap(
|
|
14157
|
+
({ conversion }) => conversion ? [conversion] : []
|
|
14158
|
+
);
|
|
14159
|
+
}
|
|
14160
|
+
ignoredTraceIds = nextIgnoredTraceIds;
|
|
14161
|
+
}
|
|
14162
|
+
}
|
|
14163
|
+
/**
|
|
14164
|
+
* Splits an input net into the connected components created by its solved
|
|
14165
|
+
* traces. This intentionally does not depend on anchored-label placement:
|
|
14166
|
+
* a group whose anchored label failed still has the same routing topology.
|
|
14167
|
+
*/
|
|
14168
|
+
getNetConnectionComponents(connection) {
|
|
14169
|
+
const firstPinId = connection.pinIds[0];
|
|
14170
|
+
if (!firstPinId) return [];
|
|
14171
|
+
const canonicalGlobalConnNetId = this.globalConnMap.getNetConnectedToId(firstPinId);
|
|
14172
|
+
if (!canonicalGlobalConnNetId) return [];
|
|
14173
|
+
const inputPinIds = new Set(
|
|
14174
|
+
this.inputProblem.chips.flatMap(
|
|
14175
|
+
(chip) => chip.pins.map((pin) => pin.pinId)
|
|
14176
|
+
)
|
|
14177
|
+
);
|
|
14178
|
+
const pinIdsInGlobalNet = this.globalConnMap.getIdsConnectedToNet(
|
|
14179
|
+
canonicalGlobalConnNetId
|
|
14180
|
+
).filter((id) => inputPinIds.has(id));
|
|
14181
|
+
const labeledPinIds = new Set(connection.pinIds);
|
|
14182
|
+
return getTraceConnectedPinComponents({
|
|
14183
|
+
pinIds: pinIdsInGlobalNet,
|
|
14184
|
+
// Available-net-orientation traces only connect a pin to its generated
|
|
14185
|
+
// anchored label. They are removed when that label becomes inline, so
|
|
14186
|
+
// treating them as routed circuitry would leave text on a deleted wire.
|
|
14187
|
+
traces: this.traces.filter(
|
|
14188
|
+
(trace) => !isGeneratedAnchoredLabelConnector(trace)
|
|
14189
|
+
)
|
|
14190
|
+
}).map((component) => ({
|
|
14191
|
+
pinIds: component.pinIds,
|
|
14192
|
+
labeledPinIds: component.pinIds.filter(
|
|
14193
|
+
(pinId) => labeledPinIds.has(pinId)
|
|
14194
|
+
),
|
|
14195
|
+
traces: component.traces.sort(
|
|
14196
|
+
(a, b) => getTraceLength2(b) - getTraceLength2(a)
|
|
14197
|
+
)
|
|
14198
|
+
})).filter((component) => component.labeledPinIds.length > 0);
|
|
14199
|
+
}
|
|
14200
|
+
getGlobalConnNetId(connection) {
|
|
14201
|
+
const firstPinId = connection.pinIds[0];
|
|
14202
|
+
if (!firstPinId) return void 0;
|
|
14203
|
+
const connectionPinIds = new Set(connection.pinIds);
|
|
14204
|
+
return this.traces.find(
|
|
14205
|
+
(trace) => trace.pins.some((pin) => connectionPinIds.has(pin.pinId))
|
|
14206
|
+
)?.globalConnNetId ?? this.inputNetLabelPlacements.find(
|
|
14207
|
+
(placement) => placement.netId === connection.netId
|
|
14208
|
+
)?.globalConnNetId ?? this.globalConnMap.getNetConnectedToId(firstPinId) ?? void 0;
|
|
14209
|
+
}
|
|
14210
|
+
/**
|
|
14211
|
+
* Converts every conventional label representation for an opted-in named
|
|
14212
|
+
* net. Routed connected components become labels on their representative
|
|
14213
|
+
* trace; disconnected pins become outward terminal stubs. The conversion is
|
|
14214
|
+
* atomic so one blocked candidate cannot leave mixed label styles on a net.
|
|
14215
|
+
*/
|
|
14216
|
+
computeNetConnectionInlinePlacements(connection, ignoredTraceIds, forcedTerminalTraceIds) {
|
|
14217
|
+
const components = this.getNetConnectionComponents(connection);
|
|
14218
|
+
const globalConnNetId = this.getGlobalConnNetId(connection);
|
|
14219
|
+
if (!globalConnNetId) return null;
|
|
14220
|
+
const inlinePlacements = [];
|
|
14221
|
+
const supersededTraceIds = /* @__PURE__ */ new Set();
|
|
14222
|
+
for (const component of components) {
|
|
14223
|
+
const shouldUseTerminalStubs = component.traces.some(
|
|
14224
|
+
(trace) => forcedTerminalTraceIds.has(trace.mspPairId)
|
|
14225
|
+
);
|
|
14226
|
+
let inlinePlacement = null;
|
|
14227
|
+
if (!shouldUseTerminalStubs) {
|
|
14228
|
+
for (const trace of component.traces) {
|
|
14229
|
+
inlinePlacement = this.computeInlinePlacement({
|
|
14230
|
+
connection,
|
|
14231
|
+
trace,
|
|
14232
|
+
pinIds: component.pinIds,
|
|
14233
|
+
ignoredTraceIds
|
|
14234
|
+
});
|
|
14235
|
+
if (inlinePlacement) break;
|
|
14236
|
+
}
|
|
14237
|
+
}
|
|
14238
|
+
if (inlinePlacement) {
|
|
14239
|
+
inlinePlacements.push(inlinePlacement);
|
|
14240
|
+
continue;
|
|
14241
|
+
}
|
|
14242
|
+
if (component.traces.length > 0 && !shouldUseTerminalStubs) {
|
|
14243
|
+
return null;
|
|
14244
|
+
}
|
|
14245
|
+
if (component.labeledPinIds.length !== component.pinIds.length) {
|
|
14246
|
+
return null;
|
|
14247
|
+
}
|
|
14248
|
+
const terminalPlacements = component.pinIds.map(
|
|
14249
|
+
(pinId) => this.computeTerminalInlinePlacement(
|
|
14250
|
+
connection,
|
|
14251
|
+
pinId,
|
|
14252
|
+
globalConnNetId,
|
|
14253
|
+
ignoredTraceIds
|
|
14254
|
+
)
|
|
14255
|
+
);
|
|
14256
|
+
if (terminalPlacements.some((placement) => placement === null)) {
|
|
14257
|
+
return null;
|
|
14258
|
+
}
|
|
14259
|
+
inlinePlacements.push(
|
|
14260
|
+
...terminalPlacements.filter(
|
|
14261
|
+
(placement) => placement !== null
|
|
14262
|
+
)
|
|
14263
|
+
);
|
|
14264
|
+
for (const trace of component.traces) {
|
|
14265
|
+
supersededTraceIds.add(trace.mspPairId);
|
|
14266
|
+
}
|
|
14267
|
+
}
|
|
14268
|
+
return { globalConnNetId, placements: inlinePlacements, supersededTraceIds };
|
|
14269
|
+
}
|
|
13818
14270
|
/**
|
|
13819
14271
|
* Converts one conventional endpoint placement into an inline label on a
|
|
13820
14272
|
* generated outward stub. The stub follows the pin's true facing direction;
|
|
13821
14273
|
* an anchored label may finish in another direction after an elbow, which is
|
|
13822
14274
|
* not the direction a terminal stub should leave the pin.
|
|
13823
14275
|
*/
|
|
13824
|
-
computeTerminalInlinePlacement(connection, pinId) {
|
|
14276
|
+
computeTerminalInlinePlacement(connection, pinId, knownGlobalConnNetId, ignoredTraceIds = /* @__PURE__ */ new Set()) {
|
|
13825
14277
|
if (!connection.netId) return null;
|
|
13826
14278
|
const anchoredPlacement = this.inputNetLabelPlacements.find(
|
|
13827
14279
|
(placement) => placement.netId === connection.netId && placement.pinIds.length === 1 && placement.pinIds[0] === pinId
|
|
13828
14280
|
);
|
|
13829
|
-
|
|
14281
|
+
const globalConnNetId = knownGlobalConnNetId ?? anchoredPlacement?.globalConnNetId;
|
|
14282
|
+
if (!globalConnNetId) return null;
|
|
13830
14283
|
const inputChip = this.inputProblem.chips.find(
|
|
13831
14284
|
(chip) => chip.pins.some((pin) => pin.pinId === pinId)
|
|
13832
14285
|
);
|
|
@@ -13835,6 +14288,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13835
14288
|
const netLabelText = connection.netLabelText?.trim() || void 0;
|
|
13836
14289
|
const width = connection.inlineNetLabelWidth ?? connection.netLabelWidth ?? estimateInlineNetLabelWidth(netLabelText ?? connection.netId, height);
|
|
13837
14290
|
const stubLength = Math.max(width + 0.2, 0.6);
|
|
14291
|
+
if (!inputPin && !anchoredPlacement) return null;
|
|
13838
14292
|
const start = inputPin ? { x: inputPin.x, y: inputPin.y } : anchoredPlacement.anchorPoint;
|
|
13839
14293
|
const direction = inputPin && inputChip ? inputPin._facingDirection ?? getPinDirection(inputPin, inputChip) : anchoredPlacement.orientation;
|
|
13840
14294
|
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 +14297,60 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13843
14297
|
intendedEnd,
|
|
13844
14298
|
minimumLength: width + 2 * INLINE_NET_LABEL_TRACE_MARGIN,
|
|
13845
14299
|
traces: this.traces,
|
|
13846
|
-
ownGlobalConnNetId:
|
|
14300
|
+
ownGlobalConnNetId: globalConnNetId,
|
|
14301
|
+
ignoredTraceIds
|
|
13847
14302
|
});
|
|
13848
14303
|
if (!end) return null;
|
|
13849
14304
|
const axis = direction === "x+" || direction === "x-" ? "x" : "y";
|
|
13850
|
-
const side = axis === "x" ? "y+" : "x-";
|
|
13851
14305
|
const anchorPoint = {
|
|
13852
14306
|
x: (start.x + end.x) / 2,
|
|
13853
14307
|
y: (start.y + end.y) / 2
|
|
13854
14308
|
};
|
|
13855
14309
|
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
|
-
|
|
14310
|
+
const sides = axis === "x" ? ["y+", "y-"] : ["x-", "x+"];
|
|
14311
|
+
for (const side of sides) {
|
|
14312
|
+
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 };
|
|
14313
|
+
const halfAlong = width / 2;
|
|
14314
|
+
const halfAcross = height / 2;
|
|
14315
|
+
const bounds = axis === "x" ? {
|
|
14316
|
+
minX: center.x - halfAlong,
|
|
14317
|
+
maxX: center.x + halfAlong,
|
|
14318
|
+
minY: center.y - halfAcross,
|
|
14319
|
+
maxY: center.y + halfAcross
|
|
14320
|
+
} : {
|
|
14321
|
+
minX: center.x - halfAcross,
|
|
14322
|
+
maxX: center.x + halfAcross,
|
|
14323
|
+
minY: center.y - halfAlong,
|
|
14324
|
+
maxY: center.y + halfAlong
|
|
14325
|
+
};
|
|
14326
|
+
if (this.isObstructed(bounds, {
|
|
14327
|
+
ownGlobalConnNetId: globalConnNetId,
|
|
14328
|
+
ignoredTraceIds
|
|
14329
|
+
})) {
|
|
14330
|
+
continue;
|
|
14331
|
+
}
|
|
14332
|
+
return {
|
|
14333
|
+
globalConnNetId,
|
|
14334
|
+
netId: connection.netId,
|
|
14335
|
+
netLabelText,
|
|
14336
|
+
pinIds: [pinId],
|
|
14337
|
+
stubTracePath: [start, end],
|
|
14338
|
+
axis,
|
|
14339
|
+
anchorPoint,
|
|
14340
|
+
center,
|
|
14341
|
+
width,
|
|
14342
|
+
height,
|
|
14343
|
+
side
|
|
14344
|
+
};
|
|
13874
14345
|
}
|
|
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
|
-
};
|
|
14346
|
+
return null;
|
|
13888
14347
|
}
|
|
13889
|
-
computeInlinePlacement(
|
|
13890
|
-
|
|
13891
|
-
|
|
13892
|
-
|
|
14348
|
+
computeInlinePlacement({
|
|
14349
|
+
connection,
|
|
14350
|
+
trace,
|
|
14351
|
+
pinIds,
|
|
14352
|
+
ignoredTraceIds = /* @__PURE__ */ new Set()
|
|
14353
|
+
}) {
|
|
13893
14354
|
const segments = getAxisAlignedSegments(trace.tracePath);
|
|
13894
14355
|
if (segments.length === 0) return null;
|
|
13895
14356
|
const height = connection.inlineNetLabelHeight ?? DEFAULT_INLINE_NET_LABEL_HEIGHT;
|
|
@@ -13917,7 +14378,8 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13917
14378
|
};
|
|
13918
14379
|
if (this.isObstructed(bounds, {
|
|
13919
14380
|
ownTrace: trace,
|
|
13920
|
-
ownGlobalConnNetId: trace.globalConnNetId
|
|
14381
|
+
ownGlobalConnNetId: trace.globalConnNetId,
|
|
14382
|
+
ignoredTraceIds
|
|
13921
14383
|
}))
|
|
13922
14384
|
continue;
|
|
13923
14385
|
return {
|
|
@@ -13925,7 +14387,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13925
14387
|
netId: connection.netId,
|
|
13926
14388
|
netLabelText,
|
|
13927
14389
|
mspPairId: trace.mspPairId,
|
|
13928
|
-
pinIds: [...
|
|
14390
|
+
pinIds: [...pinIds],
|
|
13929
14391
|
axis: segment.axis,
|
|
13930
14392
|
anchorPoint,
|
|
13931
14393
|
center,
|
|
@@ -13942,7 +14404,9 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13942
14404
|
netLabelText,
|
|
13943
14405
|
width,
|
|
13944
14406
|
height,
|
|
13945
|
-
offset
|
|
14407
|
+
offset,
|
|
14408
|
+
pinIds,
|
|
14409
|
+
ignoredTraceIds
|
|
13946
14410
|
});
|
|
13947
14411
|
if (spanPlacement) return spanPlacement;
|
|
13948
14412
|
return null;
|
|
@@ -13959,7 +14423,9 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13959
14423
|
netLabelText,
|
|
13960
14424
|
width,
|
|
13961
14425
|
height,
|
|
13962
|
-
offset
|
|
14426
|
+
offset,
|
|
14427
|
+
pinIds,
|
|
14428
|
+
ignoredTraceIds
|
|
13963
14429
|
}) {
|
|
13964
14430
|
const path = trace.tracePath;
|
|
13965
14431
|
if (path.length < 2) return null;
|
|
@@ -14009,7 +14475,8 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
14009
14475
|
};
|
|
14010
14476
|
if (this.isObstructed(bounds, {
|
|
14011
14477
|
ownTrace: trace,
|
|
14012
|
-
ownGlobalConnNetId: trace.globalConnNetId
|
|
14478
|
+
ownGlobalConnNetId: trace.globalConnNetId,
|
|
14479
|
+
ignoredTraceIds
|
|
14013
14480
|
}))
|
|
14014
14481
|
continue;
|
|
14015
14482
|
const anchorPoint = axis === "x" ? { x: along, y: side === "y+" ? maxY : minY } : { x: side === "x-" ? minX : maxX, y: along };
|
|
@@ -14018,7 +14485,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
14018
14485
|
netId: connection.netId,
|
|
14019
14486
|
netLabelText,
|
|
14020
14487
|
mspPairId: trace.mspPairId,
|
|
14021
|
-
pinIds: [...
|
|
14488
|
+
pinIds: [...pinIds],
|
|
14022
14489
|
axis,
|
|
14023
14490
|
anchorPoint,
|
|
14024
14491
|
center,
|
|
@@ -14036,7 +14503,8 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
14036
14503
|
*/
|
|
14037
14504
|
isObstructed(bounds, {
|
|
14038
14505
|
ownTrace,
|
|
14039
|
-
ownGlobalConnNetId
|
|
14506
|
+
ownGlobalConnNetId,
|
|
14507
|
+
ignoredTraceIds = /* @__PURE__ */ new Set()
|
|
14040
14508
|
}) {
|
|
14041
14509
|
for (const chip of this.inputProblem.chips) {
|
|
14042
14510
|
const chipBounds = {
|
|
@@ -14051,9 +14519,10 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
14051
14519
|
if (boundsOverlap(bounds, getTextBoxBounds(textBox))) return true;
|
|
14052
14520
|
}
|
|
14053
14521
|
for (const trace of this.traces) {
|
|
14522
|
+
if (ignoredTraceIds.has(trace.mspPairId)) continue;
|
|
14054
14523
|
if (ownTrace && trace.mspPairId === ownTrace.mspPairId) continue;
|
|
14055
14524
|
if (trace.globalConnNetId === ownGlobalConnNetId) continue;
|
|
14056
|
-
if (
|
|
14525
|
+
if (doesPathIntersectBounds3(trace.tracePath, bounds)) return true;
|
|
14057
14526
|
}
|
|
14058
14527
|
return false;
|
|
14059
14528
|
}
|
|
@@ -14061,36 +14530,94 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
14061
14530
|
* Net label placements superseded by an inline label. A net gets one label or
|
|
14062
14531
|
* the other, never both.
|
|
14063
14532
|
*/
|
|
14064
|
-
getSupersededNetLabelKeys() {
|
|
14533
|
+
getSupersededNetLabelKeys(placements = this.inlineNetLabelPlacements) {
|
|
14065
14534
|
const keys = /* @__PURE__ */ new Set();
|
|
14066
|
-
for (const placement of
|
|
14535
|
+
for (const placement of placements) {
|
|
14067
14536
|
keys.add(placement.globalConnNetId);
|
|
14068
14537
|
}
|
|
14069
14538
|
return keys;
|
|
14070
14539
|
}
|
|
14071
|
-
getOutputTraces(supersededNetLabelKeys) {
|
|
14540
|
+
getOutputTraces(supersededNetLabelKeys, supersededTraceIds) {
|
|
14072
14541
|
return this.traces.filter(
|
|
14073
|
-
(trace) => !(supersededNetLabelKeys.has(trace.globalConnNetId) && trace
|
|
14542
|
+
(trace) => !supersededTraceIds.has(trace.mspPairId) && !(supersededNetLabelKeys.has(trace.globalConnNetId) && isGeneratedAnchoredLabelConnector(trace))
|
|
14074
14543
|
);
|
|
14075
14544
|
}
|
|
14545
|
+
getInlineGlobalsOverlappingAnchoredLabels({
|
|
14546
|
+
inlineNetLabelPlacements,
|
|
14547
|
+
anchoredNetLabelPlacements
|
|
14548
|
+
}) {
|
|
14549
|
+
const blockedGlobalConnNetIds = /* @__PURE__ */ new Set();
|
|
14550
|
+
for (const inlinePlacement of inlineNetLabelPlacements) {
|
|
14551
|
+
const inlineBounds = getInlinePlacementBounds(inlinePlacement);
|
|
14552
|
+
for (const anchoredPlacement of anchoredNetLabelPlacements) {
|
|
14553
|
+
if (anchoredPlacement.globalConnNetId === inlinePlacement.globalConnNetId) {
|
|
14554
|
+
continue;
|
|
14555
|
+
}
|
|
14556
|
+
const anchoredBounds = getAnchoredPlacementBounds(anchoredPlacement);
|
|
14557
|
+
if (boundsOverlap(inlineBounds, anchoredBounds) || inlinePlacement.stubTracePath && doesPathIntersectBounds3(
|
|
14558
|
+
inlinePlacement.stubTracePath,
|
|
14559
|
+
anchoredBounds
|
|
14560
|
+
)) {
|
|
14561
|
+
blockedGlobalConnNetIds.add(inlinePlacement.globalConnNetId);
|
|
14562
|
+
break;
|
|
14563
|
+
}
|
|
14564
|
+
}
|
|
14565
|
+
}
|
|
14566
|
+
return blockedGlobalConnNetIds;
|
|
14567
|
+
}
|
|
14076
14568
|
buildPostProcessedOutput() {
|
|
14077
|
-
|
|
14078
|
-
|
|
14079
|
-
|
|
14080
|
-
|
|
14081
|
-
|
|
14082
|
-
|
|
14083
|
-
|
|
14084
|
-
|
|
14085
|
-
|
|
14086
|
-
|
|
14087
|
-
|
|
14088
|
-
|
|
14089
|
-
|
|
14090
|
-
|
|
14091
|
-
|
|
14092
|
-
|
|
14093
|
-
|
|
14569
|
+
let activeInlinePlacements = this.inlineNetLabelPlacements;
|
|
14570
|
+
while (true) {
|
|
14571
|
+
const supersededNetLabelKeys = this.getSupersededNetLabelKeys(
|
|
14572
|
+
activeInlinePlacements
|
|
14573
|
+
);
|
|
14574
|
+
const supersededTraceIds = new Set(
|
|
14575
|
+
[...supersededNetLabelKeys].flatMap((globalConnNetId) => [
|
|
14576
|
+
...this.supersededTraceIdsByGlobalConnNetId.get(globalConnNetId) ?? []
|
|
14577
|
+
])
|
|
14578
|
+
);
|
|
14579
|
+
const retainedNetLabelPlacements = this.inputNetLabelPlacements.filter(
|
|
14580
|
+
(placement) => !supersededNetLabelKeys.has(placement.globalConnNetId)
|
|
14581
|
+
);
|
|
14582
|
+
const outputTraces = this.getOutputTraces(
|
|
14583
|
+
supersededNetLabelKeys,
|
|
14584
|
+
supersededTraceIds
|
|
14585
|
+
);
|
|
14586
|
+
const pushed = pushAnchoredNetLabelsAwayFromInlineLabels({
|
|
14587
|
+
inputProblem: this.inputProblem,
|
|
14588
|
+
traces: outputTraces,
|
|
14589
|
+
netLabelPlacements: retainedNetLabelPlacements,
|
|
14590
|
+
inlineNetLabelPlacements: activeInlinePlacements
|
|
14591
|
+
});
|
|
14592
|
+
const blockedGlobalConnNetIds = this.getInlineGlobalsOverlappingAnchoredLabels({
|
|
14593
|
+
inlineNetLabelPlacements: activeInlinePlacements,
|
|
14594
|
+
anchoredNetLabelPlacements: pushed.netLabelPlacements
|
|
14595
|
+
});
|
|
14596
|
+
if (blockedGlobalConnNetIds.size > 0) {
|
|
14597
|
+
const shiftedInlineTerminalLabels = pushInlineTerminalLabelsAwayFromAnchoredLabels({
|
|
14598
|
+
inputProblem: this.inputProblem,
|
|
14599
|
+
traces: pushed.traces,
|
|
14600
|
+
anchoredNetLabelPlacements: pushed.netLabelPlacements,
|
|
14601
|
+
inlineNetLabelPlacements: activeInlinePlacements
|
|
14602
|
+
});
|
|
14603
|
+
if (shiftedInlineTerminalLabels.movedGroupCount > 0) {
|
|
14604
|
+
activeInlinePlacements = shiftedInlineTerminalLabels.inlineNetLabelPlacements;
|
|
14605
|
+
continue;
|
|
14606
|
+
}
|
|
14607
|
+
}
|
|
14608
|
+
if (blockedGlobalConnNetIds.size === 0) {
|
|
14609
|
+
this.inlineNetLabelPlacements = activeInlinePlacements;
|
|
14610
|
+
this.stats.pushedAnchoredNetLabelCount = pushed.movedLabelCount;
|
|
14611
|
+
return {
|
|
14612
|
+
traces: pushed.traces,
|
|
14613
|
+
netLabelPlacements: pushed.netLabelPlacements,
|
|
14614
|
+
inlineNetLabelPlacements: activeInlinePlacements
|
|
14615
|
+
};
|
|
14616
|
+
}
|
|
14617
|
+
activeInlinePlacements = activeInlinePlacements.filter(
|
|
14618
|
+
(placement) => !blockedGlobalConnNetIds.has(placement.globalConnNetId)
|
|
14619
|
+
);
|
|
14620
|
+
}
|
|
14094
14621
|
}
|
|
14095
14622
|
getOutput() {
|
|
14096
14623
|
if (this.postProcessedOutput) return this.postProcessedOutput;
|
|
@@ -14225,7 +14752,7 @@ var getAnchorCandidates = (segment, labelWidth, step = 0.1) => {
|
|
|
14225
14752
|
offsets.push(slack / 2, -slack / 2);
|
|
14226
14753
|
return offsets.map((offset) => pointAt(mid + offset * direction));
|
|
14227
14754
|
};
|
|
14228
|
-
var
|
|
14755
|
+
var doesPathIntersectBounds3 = (path, bounds) => {
|
|
14229
14756
|
for (let i = 0; i < path.length - 1; i++) {
|
|
14230
14757
|
const a = path[i];
|
|
14231
14758
|
const b = path[i + 1];
|
|
@@ -14245,7 +14772,8 @@ var getCollisionLimitedTerminalStubEnd = ({
|
|
|
14245
14772
|
intendedEnd,
|
|
14246
14773
|
minimumLength,
|
|
14247
14774
|
traces,
|
|
14248
|
-
ownGlobalConnNetId
|
|
14775
|
+
ownGlobalConnNetId,
|
|
14776
|
+
ignoredTraceIds
|
|
14249
14777
|
}) => {
|
|
14250
14778
|
const isHorizontal4 = Math.abs(intendedEnd.x - start.x) >= Math.abs(intendedEnd.y - start.y);
|
|
14251
14779
|
const alongAxis = isHorizontal4 ? "x" : "y";
|
|
@@ -14254,6 +14782,7 @@ var getCollisionLimitedTerminalStubEnd = ({
|
|
|
14254
14782
|
const intendedLength = Math.abs(intendedEnd[alongAxis] - start[alongAxis]);
|
|
14255
14783
|
let availableLength = intendedLength;
|
|
14256
14784
|
for (const trace of traces) {
|
|
14785
|
+
if (ignoredTraceIds.has(trace.mspPairId)) continue;
|
|
14257
14786
|
if (trace.globalConnNetId === ownGlobalConnNetId) continue;
|
|
14258
14787
|
for (let segmentIndex = 0; segmentIndex < trace.tracePath.length - 1; segmentIndex++) {
|
|
14259
14788
|
const segmentStart = trace.tracePath[segmentIndex];
|