@tscircuit/schematic-trace-solver 0.0.145 → 0.0.147
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 +9 -2
- package/dist/index.js +482 -86
- package/lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts +38 -30
- package/lib/solvers/InlineNetLabelSolver/InlineNetLabelSolver.ts +30 -8
- package/lib/solvers/InlineNetLabelSolver/pushAnchoredNetLabelsAwayFromInlineLabels.ts +530 -0
- package/lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver.ts +6 -21
- package/lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/SchematicTraceSingleLineSolver2.ts +7 -23
- package/lib/solvers/TraceAnchoredNetLabelOverlapSolver/candidates.ts +7 -14
- package/lib/types/InputProblem.ts +8 -0
- package/lib/utils/getNetLabelWidthForConnection.ts +63 -0
- package/package.json +1 -1
- package/tests/assets/inline-net-label-anchored-label-clearance.json +56 -0
- package/tests/repros/__snapshots__/repro-ti-power-output-section.snap.svg +80 -0
- package/tests/repros/repro-ti-power-output-section.input.ts +341 -0
- package/tests/repros/repro-ti-power-output-section.test.ts +13 -0
- package/tests/solvers/InlineNetLabelSolver/__snapshots__/fallback-net-label-width.snap.svg +69 -0
- package/tests/solvers/InlineNetLabelSolver/__snapshots__/inline-net-label-anchored-label-clearance.snap.svg +54 -0
- package/tests/solvers/InlineNetLabelSolver/fallback-net-label-width.test.ts +152 -0
- package/tests/solvers/InlineNetLabelSolver/inline-net-label-anchored-label-clearance.test.ts +28 -0
- package/tests/solvers/InlineNetLabelSolver/push-anchored-net-labels-away.test.ts +227 -0
package/dist/index.js
CHANGED
|
@@ -678,6 +678,50 @@ import "graphics-debug";
|
|
|
678
678
|
// lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/SchematicTraceSingleLineSolver2.ts
|
|
679
679
|
import { calculateElbow as calculateElbow2 } from "calculate-elbow";
|
|
680
680
|
|
|
681
|
+
// lib/utils/getNetLabelWidthForConnection.ts
|
|
682
|
+
var getConfiguredWidth = (connections, includeFallbackNetLabelWidth) => {
|
|
683
|
+
const explicitWidth = connections.find(
|
|
684
|
+
(connection) => connection?.netLabelWidth !== void 0
|
|
685
|
+
)?.netLabelWidth;
|
|
686
|
+
if (explicitWidth !== void 0) return explicitWidth;
|
|
687
|
+
if (!includeFallbackNetLabelWidth) return void 0;
|
|
688
|
+
return connections.find(
|
|
689
|
+
(connection) => connection?.fallbackNetLabelWidth !== void 0
|
|
690
|
+
)?.fallbackNetLabelWidth;
|
|
691
|
+
};
|
|
692
|
+
var getNetLabelWidthForConnection = ({
|
|
693
|
+
inputProblem,
|
|
694
|
+
netId,
|
|
695
|
+
pinIds,
|
|
696
|
+
includeFallbackNetLabelWidth = true
|
|
697
|
+
}) => {
|
|
698
|
+
if (netId) {
|
|
699
|
+
const widthByNetId = getConfiguredWidth(
|
|
700
|
+
[
|
|
701
|
+
inputProblem.netConnections.find(
|
|
702
|
+
(connection) => connection.netId === netId
|
|
703
|
+
),
|
|
704
|
+
inputProblem.directConnections.find(
|
|
705
|
+
(connection) => connection.netId === netId
|
|
706
|
+
)
|
|
707
|
+
],
|
|
708
|
+
includeFallbackNetLabelWidth
|
|
709
|
+
);
|
|
710
|
+
if (widthByNetId !== void 0) return widthByNetId;
|
|
711
|
+
}
|
|
712
|
+
return getConfiguredWidth(
|
|
713
|
+
[
|
|
714
|
+
inputProblem.directConnections.find(
|
|
715
|
+
(connection) => connection.pinIds.some((pinId) => pinIds.includes(pinId))
|
|
716
|
+
),
|
|
717
|
+
inputProblem.netConnections.find(
|
|
718
|
+
(connection) => connection.pinIds.some((pinId) => pinIds.includes(pinId))
|
|
719
|
+
)
|
|
720
|
+
],
|
|
721
|
+
includeFallbackNetLabelWidth
|
|
722
|
+
);
|
|
723
|
+
};
|
|
724
|
+
|
|
681
725
|
// lib/utils/textBoxBounds.ts
|
|
682
726
|
function getTextBoxBounds(textBox, padding = {}) {
|
|
683
727
|
return {
|
|
@@ -1281,7 +1325,12 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1281
1325
|
const netId = this.connectionPair?.userNetId;
|
|
1282
1326
|
if (!netId) return {};
|
|
1283
1327
|
const orientations = this.inputProblem.availableNetLabelOrientations[netId] ?? ["x+", "x-", "y+", "y-"];
|
|
1284
|
-
const netLabelWidth =
|
|
1328
|
+
const netLabelWidth = getNetLabelWidthForConnection({
|
|
1329
|
+
inputProblem: this.inputProblem,
|
|
1330
|
+
netId,
|
|
1331
|
+
pinIds: this.pins.map((pin) => pin.pinId),
|
|
1332
|
+
includeFallbackNetLabelWidth: false
|
|
1333
|
+
});
|
|
1285
1334
|
const netLabelHeight = this.getNetLabelHeightForConnectionPair(netId);
|
|
1286
1335
|
const padding = {
|
|
1287
1336
|
minX: 0,
|
|
@@ -1315,24 +1364,6 @@ var SchematicTraceSingleLineSolver2 = class extends BaseSolver {
|
|
|
1315
1364
|
}
|
|
1316
1365
|
return padding;
|
|
1317
1366
|
}
|
|
1318
|
-
getNetLabelWidthForConnectionPair(netId) {
|
|
1319
|
-
const ncWidth = this.inputProblem.netConnections.find(
|
|
1320
|
-
(nc) => nc.netId === netId
|
|
1321
|
-
)?.netLabelWidth;
|
|
1322
|
-
if (ncWidth !== void 0) return ncWidth;
|
|
1323
|
-
const dcWidthByNetId = this.inputProblem.directConnections.find(
|
|
1324
|
-
(dc) => dc.netId === netId
|
|
1325
|
-
)?.netLabelWidth;
|
|
1326
|
-
if (dcWidthByNetId !== void 0) return dcWidthByNetId;
|
|
1327
|
-
const pinIds = this.pins.map((p) => p.pinId);
|
|
1328
|
-
const dcWidthByPinId = this.inputProblem.directConnections.find(
|
|
1329
|
-
(dc) => dc.pinIds.some((pid) => pinIds.includes(pid))
|
|
1330
|
-
)?.netLabelWidth;
|
|
1331
|
-
if (dcWidthByPinId !== void 0) return dcWidthByPinId;
|
|
1332
|
-
return this.inputProblem.netConnections.find(
|
|
1333
|
-
(nc) => nc.pinIds.some((pid) => pinIds.includes(pid))
|
|
1334
|
-
)?.netLabelWidth;
|
|
1335
|
-
}
|
|
1336
1367
|
getNetLabelHeightForConnectionPair(netId) {
|
|
1337
1368
|
const ncHeight = this.inputProblem.netConnections.find(
|
|
1338
1369
|
(nc) => nc.netId === netId
|
|
@@ -3217,27 +3248,15 @@ var NetLabelPlacementSolver = class extends BaseSolver {
|
|
|
3217
3248
|
return groups;
|
|
3218
3249
|
}
|
|
3219
3250
|
getNetLabelWidthForGroup(group) {
|
|
3220
|
-
if (group.netId) {
|
|
3221
|
-
const ncWidth = this.inputProblem.netConnections.find(
|
|
3222
|
-
(nc) => nc.netId === group.netId
|
|
3223
|
-
)?.netLabelWidth;
|
|
3224
|
-
if (ncWidth !== void 0) return ncWidth;
|
|
3225
|
-
const dcWidthByNetId = this.inputProblem.directConnections.find(
|
|
3226
|
-
(dc) => dc.netId === group.netId
|
|
3227
|
-
)?.netLabelWidth;
|
|
3228
|
-
if (dcWidthByNetId !== void 0) return dcWidthByNetId;
|
|
3229
|
-
}
|
|
3230
3251
|
const pinIds = group.overlappingTraces?.pins.map((p) => p.pinId) ?? [];
|
|
3231
3252
|
if (group.portOnlyPinId) {
|
|
3232
3253
|
pinIds.push(group.portOnlyPinId);
|
|
3233
3254
|
}
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
(nc) => nc.pinIds.some((pid) => pinIds.includes(pid))
|
|
3240
|
-
)?.netLabelWidth;
|
|
3255
|
+
return getNetLabelWidthForConnection({
|
|
3256
|
+
inputProblem: this.inputProblem,
|
|
3257
|
+
netId: group.netId,
|
|
3258
|
+
pinIds
|
|
3259
|
+
});
|
|
3241
3260
|
}
|
|
3242
3261
|
getNetLabelHeightForGroup(group) {
|
|
3243
3262
|
if (group.netId) {
|
|
@@ -8527,13 +8546,21 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8527
8546
|
const bY = this.outputNetLabelPlacements[b].anchorPoint.y;
|
|
8528
8547
|
return requiredOrientation === "y+" ? bY - aY : aY - bY;
|
|
8529
8548
|
});
|
|
8530
|
-
const blockedLabelWidth =
|
|
8549
|
+
const blockedLabelWidth = getNetLabelWidthForConnection({
|
|
8550
|
+
inputProblem: this.inputProblem,
|
|
8551
|
+
netId: blockedLabel.netId,
|
|
8552
|
+
pinIds: blockedLabel.pinIds
|
|
8553
|
+
});
|
|
8531
8554
|
let columnLabelIndex;
|
|
8532
8555
|
if (blockedLabelWidth !== void 0) {
|
|
8533
8556
|
columnLabelIndex = labelsToOrder.find((index) => {
|
|
8534
8557
|
if (index === blockedStandaloneLabelIndex) return false;
|
|
8535
8558
|
const label = this.outputNetLabelPlacements[index];
|
|
8536
|
-
return
|
|
8559
|
+
return getNetLabelWidthForConnection({
|
|
8560
|
+
inputProblem: this.inputProblem,
|
|
8561
|
+
netId: label.netId,
|
|
8562
|
+
pinIds: label.pinIds
|
|
8563
|
+
}) === blockedLabelWidth;
|
|
8537
8564
|
});
|
|
8538
8565
|
}
|
|
8539
8566
|
if (columnLabelIndex !== void 0) {
|
|
@@ -8754,7 +8781,11 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
8754
8781
|
if (!chip) return null;
|
|
8755
8782
|
const { width, height } = getDimsForOrientation({
|
|
8756
8783
|
orientation,
|
|
8757
|
-
netLabelWidth:
|
|
8784
|
+
netLabelWidth: getNetLabelWidthForConnection({
|
|
8785
|
+
inputProblem: this.inputProblem,
|
|
8786
|
+
netId: label.netId,
|
|
8787
|
+
pinIds: label.pinIds
|
|
8788
|
+
}),
|
|
8758
8789
|
netLabelHeight: this.getNetLabelHeight(label)
|
|
8759
8790
|
});
|
|
8760
8791
|
const nextPinToRight = this.outputNetLabelPlacements.map((otherLabel, index) => ({
|
|
@@ -9188,7 +9219,11 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
9188
9219
|
labelIntersectsDifferentNetTrace(label) {
|
|
9189
9220
|
const { width, height } = getDimsForOrientation({
|
|
9190
9221
|
orientation: label.orientation,
|
|
9191
|
-
netLabelWidth:
|
|
9222
|
+
netLabelWidth: getNetLabelWidthForConnection({
|
|
9223
|
+
inputProblem: this.inputProblem,
|
|
9224
|
+
netId: label.netId,
|
|
9225
|
+
pinIds: label.pinIds
|
|
9226
|
+
}),
|
|
9192
9227
|
netLabelHeight: this.getNetLabelHeight(label)
|
|
9193
9228
|
});
|
|
9194
9229
|
const center = getCenterFromAnchor(
|
|
@@ -9206,7 +9241,11 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
9206
9241
|
const anchorPoint = this.getWickOffsetAnchor(label.anchorPoint, orientation);
|
|
9207
9242
|
const { width, height } = getDimsForOrientation({
|
|
9208
9243
|
orientation,
|
|
9209
|
-
netLabelWidth:
|
|
9244
|
+
netLabelWidth: getNetLabelWidthForConnection({
|
|
9245
|
+
inputProblem: this.inputProblem,
|
|
9246
|
+
netId: label.netId,
|
|
9247
|
+
pinIds: label.pinIds
|
|
9248
|
+
}),
|
|
9210
9249
|
netLabelHeight: this.getNetLabelHeight(label)
|
|
9211
9250
|
});
|
|
9212
9251
|
const searchStartAnchor = this.getSideOffsetAnchor({
|
|
@@ -9261,7 +9300,11 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
9261
9300
|
getSearchDistanceLimit(label, orientation) {
|
|
9262
9301
|
const { width, height } = getDimsForOrientation({
|
|
9263
9302
|
orientation,
|
|
9264
|
-
netLabelWidth:
|
|
9303
|
+
netLabelWidth: getNetLabelWidthForConnection({
|
|
9304
|
+
inputProblem: this.inputProblem,
|
|
9305
|
+
netId: label.netId,
|
|
9306
|
+
pinIds: label.pinIds
|
|
9307
|
+
}),
|
|
9265
9308
|
netLabelHeight: this.getNetLabelHeight(label)
|
|
9266
9309
|
});
|
|
9267
9310
|
const labelLength = orientation === "y+" || orientation === "y-" ? height : width;
|
|
@@ -9312,7 +9355,11 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
9312
9355
|
createCandidate(label, anchorPoint, orientation, connectorSource) {
|
|
9313
9356
|
const { width, height } = getDimsForOrientation({
|
|
9314
9357
|
orientation,
|
|
9315
|
-
netLabelWidth:
|
|
9358
|
+
netLabelWidth: getNetLabelWidthForConnection({
|
|
9359
|
+
inputProblem: this.inputProblem,
|
|
9360
|
+
netId: label.netId,
|
|
9361
|
+
pinIds: label.pinIds
|
|
9362
|
+
}),
|
|
9316
9363
|
netLabelHeight: this.getNetLabelHeight(label)
|
|
9317
9364
|
});
|
|
9318
9365
|
return {
|
|
@@ -9324,25 +9371,6 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
9324
9371
|
center: getCenterFromAnchor(anchorPoint, orientation, width, height)
|
|
9325
9372
|
};
|
|
9326
9373
|
}
|
|
9327
|
-
getNetLabelWidth(label) {
|
|
9328
|
-
if (label.netId) {
|
|
9329
|
-
const ncWidth = this.inputProblem.netConnections.find(
|
|
9330
|
-
(connection) => connection.netId === label.netId
|
|
9331
|
-
)?.netLabelWidth;
|
|
9332
|
-
if (ncWidth !== void 0) return ncWidth;
|
|
9333
|
-
const dcWidthByNetId = this.inputProblem.directConnections.find(
|
|
9334
|
-
(dc) => dc.netId === label.netId
|
|
9335
|
-
)?.netLabelWidth;
|
|
9336
|
-
if (dcWidthByNetId !== void 0) return dcWidthByNetId;
|
|
9337
|
-
}
|
|
9338
|
-
const dcWidthByPinId = this.inputProblem.directConnections.find(
|
|
9339
|
-
(dc) => dc.pinIds.some((pid) => label.pinIds.includes(pid))
|
|
9340
|
-
)?.netLabelWidth;
|
|
9341
|
-
if (dcWidthByPinId !== void 0) return dcWidthByPinId;
|
|
9342
|
-
return this.inputProblem.netConnections.find(
|
|
9343
|
-
(nc) => nc.pinIds.some((pid) => label.pinIds.includes(pid))
|
|
9344
|
-
)?.netLabelWidth;
|
|
9345
|
-
}
|
|
9346
9374
|
getNetLabelHeight(label) {
|
|
9347
9375
|
if (label.netId) {
|
|
9348
9376
|
const ncHeight = this.inputProblem.netConnections.find(
|
|
@@ -10541,18 +10569,12 @@ var getChipBounds = (inputProblem) => {
|
|
|
10541
10569
|
};
|
|
10542
10570
|
};
|
|
10543
10571
|
var getNetLabelWidth = (inputProblem, label) => {
|
|
10544
|
-
const
|
|
10545
|
-
|
|
10546
|
-
|
|
10547
|
-
|
|
10548
|
-
|
|
10549
|
-
|
|
10550
|
-
)?.netLabelWidth;
|
|
10551
|
-
if (dcWidth !== void 0) return dcWidth;
|
|
10552
|
-
const ncWidthByPinId = inputProblem.netConnections.find(
|
|
10553
|
-
(nc) => nc.pinIds.some((pid) => label.pinIds.includes(pid))
|
|
10554
|
-
)?.netLabelWidth;
|
|
10555
|
-
if (ncWidthByPinId !== void 0) return ncWidthByPinId;
|
|
10572
|
+
const configuredWidth = getNetLabelWidthForConnection({
|
|
10573
|
+
inputProblem,
|
|
10574
|
+
netId: label.netId,
|
|
10575
|
+
pinIds: label.pinIds
|
|
10576
|
+
});
|
|
10577
|
+
if (configuredWidth !== void 0) return configuredWidth;
|
|
10556
10578
|
if (label.orientation === "y+" || label.orientation === "y-") {
|
|
10557
10579
|
return label.height;
|
|
10558
10580
|
}
|
|
@@ -10958,10 +10980,10 @@ function isPointOnPath(point, path) {
|
|
|
10958
10980
|
}
|
|
10959
10981
|
function buildMergedObstacleLabel(seedLabel, allLabels) {
|
|
10960
10982
|
const TOUCH_MARGIN = 0.01;
|
|
10961
|
-
const
|
|
10983
|
+
const getBounds4 = (l) => getRectBounds(l.center, l.width, l.height);
|
|
10962
10984
|
const touches = (a, b) => {
|
|
10963
|
-
const ba =
|
|
10964
|
-
const bb =
|
|
10985
|
+
const ba = getBounds4(a);
|
|
10986
|
+
const bb = getBounds4(b);
|
|
10965
10987
|
return ba.minX <= bb.maxX + TOUCH_MARGIN && ba.maxX >= bb.minX - TOUCH_MARGIN && ba.minY <= bb.maxY + TOUCH_MARGIN && ba.maxY >= bb.minY - TOUCH_MARGIN;
|
|
10966
10988
|
};
|
|
10967
10989
|
const group = /* @__PURE__ */ new Set([seedLabel]);
|
|
@@ -10978,7 +11000,7 @@ function buildMergedObstacleLabel(seedLabel, allLabels) {
|
|
|
10978
11000
|
}
|
|
10979
11001
|
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
10980
11002
|
for (const l of group) {
|
|
10981
|
-
const b =
|
|
11003
|
+
const b = getBounds4(l);
|
|
10982
11004
|
if (b.minX < minX) minX = b.minX;
|
|
10983
11005
|
if (b.minY < minY) minY = b.minY;
|
|
10984
11006
|
if (b.maxX > maxX) maxX = b.maxX;
|
|
@@ -12789,6 +12811,365 @@ var alignPortOnlyInlineNetLabelStubs = ({
|
|
|
12789
12811
|
return alignedPlacements;
|
|
12790
12812
|
};
|
|
12791
12813
|
|
|
12814
|
+
// lib/solvers/InlineNetLabelSolver/pushAnchoredNetLabelsAwayFromInlineLabels.ts
|
|
12815
|
+
var LABEL_CLEARANCE2 = 0.05;
|
|
12816
|
+
var POINT_EPSILON = 1e-6;
|
|
12817
|
+
var CONTIGUOUS_LABEL_GAP = 0.01;
|
|
12818
|
+
var MAX_OUTWARD_DISTANCE = 5;
|
|
12819
|
+
var getBounds3 = (placement) => {
|
|
12820
|
+
const renderedWidth = placement.axis === "y" ? placement.height : placement.width;
|
|
12821
|
+
const renderedHeight = placement.axis === "y" ? placement.width : placement.height;
|
|
12822
|
+
return {
|
|
12823
|
+
minX: placement.center.x - renderedWidth / 2,
|
|
12824
|
+
maxX: placement.center.x + renderedWidth / 2,
|
|
12825
|
+
minY: placement.center.y - renderedHeight / 2,
|
|
12826
|
+
maxY: placement.center.y + renderedHeight / 2
|
|
12827
|
+
};
|
|
12828
|
+
};
|
|
12829
|
+
var pointsEqual3 = (a, b) => Math.abs(a.x - b.x) <= POINT_EPSILON && Math.abs(a.y - b.y) <= POINT_EPSILON;
|
|
12830
|
+
var pathIntersectsBounds = (path, bounds) => {
|
|
12831
|
+
for (let index = 0; index < path.length - 1; index++) {
|
|
12832
|
+
const start = path[index];
|
|
12833
|
+
const end = path[index + 1];
|
|
12834
|
+
const segmentBounds = {
|
|
12835
|
+
minX: Math.min(start.x, end.x),
|
|
12836
|
+
maxX: Math.max(start.x, end.x),
|
|
12837
|
+
minY: Math.min(start.y, end.y),
|
|
12838
|
+
maxY: Math.max(start.y, end.y)
|
|
12839
|
+
};
|
|
12840
|
+
if (boundsOverlap(segmentBounds, bounds)) return true;
|
|
12841
|
+
}
|
|
12842
|
+
return false;
|
|
12843
|
+
};
|
|
12844
|
+
var isPointOnPath2 = (point, path) => {
|
|
12845
|
+
for (let index = 0; index < path.length - 1; index++) {
|
|
12846
|
+
const start = path[index];
|
|
12847
|
+
const end = path[index + 1];
|
|
12848
|
+
const minX = Math.min(start.x, end.x) - POINT_EPSILON;
|
|
12849
|
+
const maxX = Math.max(start.x, end.x) + POINT_EPSILON;
|
|
12850
|
+
const minY = Math.min(start.y, end.y) - POINT_EPSILON;
|
|
12851
|
+
const maxY = Math.max(start.y, end.y) + POINT_EPSILON;
|
|
12852
|
+
const isHorizontal4 = Math.abs(start.y - end.y) <= POINT_EPSILON;
|
|
12853
|
+
const isVertical5 = Math.abs(start.x - end.x) <= POINT_EPSILON;
|
|
12854
|
+
if ((isHorizontal4 && Math.abs(point.y - start.y) <= POINT_EPSILON || isVertical5 && Math.abs(point.x - start.x) <= POINT_EPSILON) && point.x >= minX && point.x <= maxX && point.y >= minY && point.y <= maxY) {
|
|
12855
|
+
return true;
|
|
12856
|
+
}
|
|
12857
|
+
}
|
|
12858
|
+
return false;
|
|
12859
|
+
};
|
|
12860
|
+
var getRequiredOutwardDistance = (label, inlineBounds) => {
|
|
12861
|
+
const labelBounds = getBounds3(label);
|
|
12862
|
+
if (label.orientation === "x-" || label.orientation === "x+") {
|
|
12863
|
+
const nearby2 = inlineBounds.filter(
|
|
12864
|
+
(bounds) => labelBounds.minY < bounds.maxY && labelBounds.maxY > bounds.minY
|
|
12865
|
+
);
|
|
12866
|
+
if (nearby2.length === 0) return 0;
|
|
12867
|
+
if (label.orientation === "x-") {
|
|
12868
|
+
const targetMaxX = Math.min(...nearby2.map((bounds) => bounds.minX));
|
|
12869
|
+
return Math.max(0, labelBounds.maxX - targetMaxX + LABEL_CLEARANCE2);
|
|
12870
|
+
}
|
|
12871
|
+
const targetMinX = Math.max(...nearby2.map((bounds) => bounds.maxX));
|
|
12872
|
+
return Math.max(0, targetMinX - labelBounds.minX + LABEL_CLEARANCE2);
|
|
12873
|
+
}
|
|
12874
|
+
const nearby = inlineBounds.filter(
|
|
12875
|
+
(bounds) => labelBounds.minX < bounds.maxX && labelBounds.maxX > bounds.minX
|
|
12876
|
+
);
|
|
12877
|
+
if (nearby.length === 0) return 0;
|
|
12878
|
+
if (label.orientation === "y-") {
|
|
12879
|
+
const targetMaxY = Math.min(...nearby.map((bounds) => bounds.minY));
|
|
12880
|
+
return Math.max(0, labelBounds.maxY - targetMaxY + LABEL_CLEARANCE2);
|
|
12881
|
+
}
|
|
12882
|
+
const targetMinY = Math.max(...nearby.map((bounds) => bounds.maxY));
|
|
12883
|
+
return Math.max(0, targetMinY - labelBounds.minY + LABEL_CLEARANCE2);
|
|
12884
|
+
};
|
|
12885
|
+
var moveLabel = (label, orientation, distance5) => {
|
|
12886
|
+
const direction = dir(orientation);
|
|
12887
|
+
return {
|
|
12888
|
+
...label,
|
|
12889
|
+
anchorPoint: {
|
|
12890
|
+
x: label.anchorPoint.x + direction.x * distance5,
|
|
12891
|
+
y: label.anchorPoint.y + direction.y * distance5
|
|
12892
|
+
},
|
|
12893
|
+
center: {
|
|
12894
|
+
x: label.center.x + direction.x * distance5,
|
|
12895
|
+
y: label.center.y + direction.y * distance5
|
|
12896
|
+
}
|
|
12897
|
+
};
|
|
12898
|
+
};
|
|
12899
|
+
var getDistanceToShoveBoundsPast = (obstacleBounds, movingBounds, orientation) => {
|
|
12900
|
+
switch (orientation) {
|
|
12901
|
+
case "x-":
|
|
12902
|
+
return obstacleBounds.maxX - movingBounds.minX + LABEL_CLEARANCE2;
|
|
12903
|
+
case "x+":
|
|
12904
|
+
return movingBounds.maxX - obstacleBounds.minX + LABEL_CLEARANCE2;
|
|
12905
|
+
case "y-":
|
|
12906
|
+
return obstacleBounds.maxY - movingBounds.minY + LABEL_CLEARANCE2;
|
|
12907
|
+
case "y+":
|
|
12908
|
+
return movingBounds.maxY - obstacleBounds.minY + LABEL_CLEARANCE2;
|
|
12909
|
+
}
|
|
12910
|
+
};
|
|
12911
|
+
var boundsGapOnPerpendicularAxis = (a, b, orientation) => {
|
|
12912
|
+
if (orientation === "x-" || orientation === "x+") {
|
|
12913
|
+
return Math.max(0, a.minY - b.maxY, b.minY - a.maxY);
|
|
12914
|
+
}
|
|
12915
|
+
return Math.max(0, a.minX - b.maxX, b.minX - a.maxX);
|
|
12916
|
+
};
|
|
12917
|
+
var sharesOwnerChip = (label, ownerChipIds, chipIdByPinId) => label.pinIds.some((pinId) => ownerChipIds.has(chipIdByPinId.get(pinId) ?? ""));
|
|
12918
|
+
var isGeneratedLabelConnector = (trace) => trace.mspPairId.startsWith("available-net-orientation-") || trace.mspPairId.startsWith("inline-net-label-clearance-");
|
|
12919
|
+
var findConnectorTraceIndex = (label, traces) => traces.findIndex((trace) => {
|
|
12920
|
+
if (trace.globalConnNetId !== label.globalConnNetId) return false;
|
|
12921
|
+
if (!isGeneratedLabelConnector(trace)) return false;
|
|
12922
|
+
const first = trace.tracePath[0];
|
|
12923
|
+
const last = trace.tracePath.at(-1);
|
|
12924
|
+
return Boolean(
|
|
12925
|
+
first && pointsEqual3(first, label.anchorPoint) || last && pointsEqual3(last, label.anchorPoint)
|
|
12926
|
+
);
|
|
12927
|
+
});
|
|
12928
|
+
var canAddConnectorAtAnchor = (label, traces, pinMap) => {
|
|
12929
|
+
if (label.pinIds.some((pinId) => {
|
|
12930
|
+
const pin = pinMap[pinId];
|
|
12931
|
+
return pin && pointsEqual3(pin, label.anchorPoint);
|
|
12932
|
+
})) {
|
|
12933
|
+
return true;
|
|
12934
|
+
}
|
|
12935
|
+
return traces.some(
|
|
12936
|
+
(trace) => trace.globalConnNetId === label.globalConnNetId && isPointOnPath2(label.anchorPoint, trace.tracePath)
|
|
12937
|
+
);
|
|
12938
|
+
};
|
|
12939
|
+
var moveConnectorEndpoint = (trace, oldAnchor, newAnchor) => {
|
|
12940
|
+
const tracePath = trace.tracePath.map((point) => ({ ...point }));
|
|
12941
|
+
if (pointsEqual3(tracePath[0], oldAnchor)) tracePath[0] = newAnchor;
|
|
12942
|
+
if (pointsEqual3(tracePath.at(-1), oldAnchor)) {
|
|
12943
|
+
tracePath[tracePath.length - 1] = newAnchor;
|
|
12944
|
+
}
|
|
12945
|
+
return { ...trace, tracePath };
|
|
12946
|
+
};
|
|
12947
|
+
var createConnectorTrace = ({
|
|
12948
|
+
label,
|
|
12949
|
+
labelIndex,
|
|
12950
|
+
newAnchor,
|
|
12951
|
+
pinMap
|
|
12952
|
+
}) => {
|
|
12953
|
+
const mspPairId = `inline-net-label-clearance-${labelIndex}-${label.netId ?? label.globalConnNetId}`;
|
|
12954
|
+
return {
|
|
12955
|
+
mspPairId,
|
|
12956
|
+
dcConnNetId: label.dcConnNetId ?? label.globalConnNetId,
|
|
12957
|
+
globalConnNetId: label.globalConnNetId,
|
|
12958
|
+
userNetId: label.netId,
|
|
12959
|
+
pins: getTracePins(label, pinMap),
|
|
12960
|
+
tracePath: [label.anchorPoint, newAnchor],
|
|
12961
|
+
mspConnectionPairIds: [mspPairId],
|
|
12962
|
+
pinIds: label.pinIds
|
|
12963
|
+
};
|
|
12964
|
+
};
|
|
12965
|
+
var getContiguousLabelGroup = ({
|
|
12966
|
+
triggerIndex,
|
|
12967
|
+
labels,
|
|
12968
|
+
chipIdByPinId
|
|
12969
|
+
}) => {
|
|
12970
|
+
const trigger = labels[triggerIndex];
|
|
12971
|
+
const ownerChipIds = new Set(
|
|
12972
|
+
trigger.pinIds.flatMap((pinId) => {
|
|
12973
|
+
const chipId = chipIdByPinId.get(pinId);
|
|
12974
|
+
return chipId ? [chipId] : [];
|
|
12975
|
+
})
|
|
12976
|
+
);
|
|
12977
|
+
const candidates = labels.map((label, labelIndex) => ({ label, labelIndex })).filter(
|
|
12978
|
+
({ label }) => label.orientation === trigger.orientation && label.mspConnectionPairIds.length === 0 && sharesOwnerChip(label, ownerChipIds, chipIdByPinId)
|
|
12979
|
+
);
|
|
12980
|
+
const group = /* @__PURE__ */ new Set([triggerIndex]);
|
|
12981
|
+
let changed = true;
|
|
12982
|
+
while (changed) {
|
|
12983
|
+
changed = false;
|
|
12984
|
+
for (const { label, labelIndex } of candidates) {
|
|
12985
|
+
if (group.has(labelIndex)) continue;
|
|
12986
|
+
if ([...group].some(
|
|
12987
|
+
(memberIndex) => boundsGapOnPerpendicularAxis(
|
|
12988
|
+
getBounds3(labels[memberIndex]),
|
|
12989
|
+
getBounds3(label),
|
|
12990
|
+
trigger.orientation
|
|
12991
|
+
) <= CONTIGUOUS_LABEL_GAP
|
|
12992
|
+
)) {
|
|
12993
|
+
group.add(labelIndex);
|
|
12994
|
+
changed = true;
|
|
12995
|
+
}
|
|
12996
|
+
}
|
|
12997
|
+
}
|
|
12998
|
+
return { group, ownerChipIds };
|
|
12999
|
+
};
|
|
13000
|
+
var pushAnchoredNetLabelsAwayFromInlineLabels = ({
|
|
13001
|
+
inputProblem,
|
|
13002
|
+
traces,
|
|
13003
|
+
netLabelPlacements,
|
|
13004
|
+
inlineNetLabelPlacements
|
|
13005
|
+
}) => {
|
|
13006
|
+
const outputTraces = traces.map((trace) => ({
|
|
13007
|
+
...trace,
|
|
13008
|
+
tracePath: trace.tracePath.map((point) => ({ ...point }))
|
|
13009
|
+
}));
|
|
13010
|
+
const outputLabels = netLabelPlacements.map((label) => ({ ...label }));
|
|
13011
|
+
const inlineBounds = inlineNetLabelPlacements.map(getBounds3);
|
|
13012
|
+
const pinMap = getPinMap(inputProblem);
|
|
13013
|
+
const chipIdByPinId = /* @__PURE__ */ new Map();
|
|
13014
|
+
for (const chip of inputProblem.chips) {
|
|
13015
|
+
for (const pin of chip.pins) chipIdByPinId.set(pin.pinId, chip.chipId);
|
|
13016
|
+
}
|
|
13017
|
+
const movedLabelIndices = /* @__PURE__ */ new Set();
|
|
13018
|
+
for (let triggerIndex = 0; triggerIndex < outputLabels.length; triggerIndex++) {
|
|
13019
|
+
const trigger = outputLabels[triggerIndex];
|
|
13020
|
+
const distance5 = getRequiredOutwardDistance(trigger, inlineBounds);
|
|
13021
|
+
if (distance5 <= POINT_EPSILON || distance5 > MAX_OUTWARD_DISTANCE) continue;
|
|
13022
|
+
const { group, ownerChipIds } = getContiguousLabelGroup({
|
|
13023
|
+
triggerIndex,
|
|
13024
|
+
labels: outputLabels,
|
|
13025
|
+
chipIdByPinId
|
|
13026
|
+
});
|
|
13027
|
+
const distances = new Map(
|
|
13028
|
+
[...group].map((labelIndex) => [labelIndex, distance5])
|
|
13029
|
+
);
|
|
13030
|
+
let failed = false;
|
|
13031
|
+
for (let iteration = 0; iteration < outputLabels.length; iteration++) {
|
|
13032
|
+
let adjustedObstacle = false;
|
|
13033
|
+
for (const [movingIndex, movingDistance] of distances) {
|
|
13034
|
+
const movingBounds = getBounds3(
|
|
13035
|
+
moveLabel(
|
|
13036
|
+
outputLabels[movingIndex],
|
|
13037
|
+
trigger.orientation,
|
|
13038
|
+
movingDistance
|
|
13039
|
+
)
|
|
13040
|
+
);
|
|
13041
|
+
for (let obstacleIndex = 0; obstacleIndex < outputLabels.length; obstacleIndex++) {
|
|
13042
|
+
if (group.has(obstacleIndex)) continue;
|
|
13043
|
+
const obstacle = outputLabels[obstacleIndex];
|
|
13044
|
+
const existingObstacleDistance = distances.get(obstacleIndex) ?? 0;
|
|
13045
|
+
const obstacleBounds = getBounds3(
|
|
13046
|
+
moveLabel(obstacle, trigger.orientation, existingObstacleDistance)
|
|
13047
|
+
);
|
|
13048
|
+
if (!boundsOverlap(movingBounds, obstacleBounds)) continue;
|
|
13049
|
+
if (!sharesOwnerChip(obstacle, ownerChipIds, chipIdByPinId) || findConnectorTraceIndex(obstacle, outputTraces) === -1 && !canAddConnectorAtAnchor(obstacle, outputTraces, pinMap)) {
|
|
13050
|
+
failed = true;
|
|
13051
|
+
break;
|
|
13052
|
+
}
|
|
13053
|
+
const shoveDistance = getDistanceToShoveBoundsPast(
|
|
13054
|
+
getBounds3(obstacle),
|
|
13055
|
+
movingBounds,
|
|
13056
|
+
trigger.orientation
|
|
13057
|
+
);
|
|
13058
|
+
if (shoveDistance > MAX_OUTWARD_DISTANCE || shoveDistance <= existingObstacleDistance + POINT_EPSILON) {
|
|
13059
|
+
failed = true;
|
|
13060
|
+
break;
|
|
13061
|
+
}
|
|
13062
|
+
distances.set(obstacleIndex, shoveDistance);
|
|
13063
|
+
adjustedObstacle = true;
|
|
13064
|
+
}
|
|
13065
|
+
if (failed) break;
|
|
13066
|
+
}
|
|
13067
|
+
if (failed || !adjustedObstacle) break;
|
|
13068
|
+
}
|
|
13069
|
+
if (failed) continue;
|
|
13070
|
+
const proposals = /* @__PURE__ */ new Map();
|
|
13071
|
+
for (const [labelIndex, labelDistance] of distances) {
|
|
13072
|
+
proposals.set(
|
|
13073
|
+
labelIndex,
|
|
13074
|
+
moveLabel(
|
|
13075
|
+
outputLabels[labelIndex],
|
|
13076
|
+
trigger.orientation,
|
|
13077
|
+
labelDistance
|
|
13078
|
+
)
|
|
13079
|
+
);
|
|
13080
|
+
}
|
|
13081
|
+
const finalLabelAt = (labelIndex) => proposals.get(labelIndex) ?? outputLabels[labelIndex];
|
|
13082
|
+
for (const [labelIndex, movedLabel] of proposals) {
|
|
13083
|
+
const movedBounds = getBounds3(movedLabel);
|
|
13084
|
+
if (inlineBounds.some((bounds) => boundsOverlap(movedBounds, bounds))) {
|
|
13085
|
+
failed = true;
|
|
13086
|
+
break;
|
|
13087
|
+
}
|
|
13088
|
+
if (inputProblem.chips.some(
|
|
13089
|
+
(chip) => boundsOverlap(movedBounds, {
|
|
13090
|
+
minX: chip.center.x - chip.width / 2,
|
|
13091
|
+
maxX: chip.center.x + chip.width / 2,
|
|
13092
|
+
minY: chip.center.y - chip.height / 2,
|
|
13093
|
+
maxY: chip.center.y + chip.height / 2
|
|
13094
|
+
})
|
|
13095
|
+
) || (inputProblem.textBoxes ?? []).some(
|
|
13096
|
+
(textBox) => boundsOverlap(movedBounds, getTextBoxBounds(textBox))
|
|
13097
|
+
)) {
|
|
13098
|
+
failed = true;
|
|
13099
|
+
break;
|
|
13100
|
+
}
|
|
13101
|
+
if (outputLabels.some(
|
|
13102
|
+
(_, otherIndex) => otherIndex !== labelIndex && boundsOverlap(movedBounds, getBounds3(finalLabelAt(otherIndex)))
|
|
13103
|
+
)) {
|
|
13104
|
+
failed = true;
|
|
13105
|
+
break;
|
|
13106
|
+
}
|
|
13107
|
+
if (outputTraces.some(
|
|
13108
|
+
(trace) => trace.globalConnNetId !== movedLabel.globalConnNetId && pathIntersectsBounds(trace.tracePath, movedBounds)
|
|
13109
|
+
)) {
|
|
13110
|
+
failed = true;
|
|
13111
|
+
break;
|
|
13112
|
+
}
|
|
13113
|
+
}
|
|
13114
|
+
if (failed) continue;
|
|
13115
|
+
const connectorUpdates = [];
|
|
13116
|
+
for (const [labelIndex, movedLabel] of proposals) {
|
|
13117
|
+
const label = outputLabels[labelIndex];
|
|
13118
|
+
const connectorIndex = findConnectorTraceIndex(label, outputTraces);
|
|
13119
|
+
if (connectorIndex === -1 && !canAddConnectorAtAnchor(label, outputTraces, pinMap)) {
|
|
13120
|
+
failed = true;
|
|
13121
|
+
break;
|
|
13122
|
+
}
|
|
13123
|
+
const connector = connectorIndex === -1 ? createConnectorTrace({
|
|
13124
|
+
label,
|
|
13125
|
+
labelIndex,
|
|
13126
|
+
newAnchor: movedLabel.anchorPoint,
|
|
13127
|
+
pinMap
|
|
13128
|
+
}) : moveConnectorEndpoint(
|
|
13129
|
+
outputTraces[connectorIndex],
|
|
13130
|
+
label.anchorPoint,
|
|
13131
|
+
movedLabel.anchorPoint
|
|
13132
|
+
);
|
|
13133
|
+
const connectorObstructed = inlineBounds.some(
|
|
13134
|
+
(bounds) => pathIntersectsBounds(connector.tracePath, bounds)
|
|
13135
|
+
) || inputProblem.chips.some(
|
|
13136
|
+
(chip) => pathIntersectsBounds(connector.tracePath, {
|
|
13137
|
+
minX: chip.center.x - chip.width / 2,
|
|
13138
|
+
maxX: chip.center.x + chip.width / 2,
|
|
13139
|
+
minY: chip.center.y - chip.height / 2,
|
|
13140
|
+
maxY: chip.center.y + chip.height / 2
|
|
13141
|
+
})
|
|
13142
|
+
) || (inputProblem.textBoxes ?? []).some(
|
|
13143
|
+
(textBox) => pathIntersectsBounds(connector.tracePath, getTextBoxBounds(textBox))
|
|
13144
|
+
) || outputLabels.some(
|
|
13145
|
+
(_, otherIndex) => otherIndex !== labelIndex && pathIntersectsBounds(
|
|
13146
|
+
connector.tracePath,
|
|
13147
|
+
getBounds3(finalLabelAt(otherIndex))
|
|
13148
|
+
)
|
|
13149
|
+
);
|
|
13150
|
+
if (connectorObstructed) {
|
|
13151
|
+
failed = true;
|
|
13152
|
+
break;
|
|
13153
|
+
}
|
|
13154
|
+
connectorUpdates.push({ labelIndex, connectorIndex, trace: connector });
|
|
13155
|
+
}
|
|
13156
|
+
if (failed) continue;
|
|
13157
|
+
for (const [labelIndex, movedLabel] of proposals) {
|
|
13158
|
+
outputLabels[labelIndex] = movedLabel;
|
|
13159
|
+
movedLabelIndices.add(labelIndex);
|
|
13160
|
+
}
|
|
13161
|
+
for (const update of connectorUpdates) {
|
|
13162
|
+
if (update.connectorIndex === -1) outputTraces.push(update.trace);
|
|
13163
|
+
else outputTraces[update.connectorIndex] = update.trace;
|
|
13164
|
+
}
|
|
13165
|
+
}
|
|
13166
|
+
return {
|
|
13167
|
+
traces: outputTraces,
|
|
13168
|
+
netLabelPlacements: outputLabels,
|
|
13169
|
+
movedLabelCount: movedLabelIndices.size
|
|
13170
|
+
};
|
|
13171
|
+
};
|
|
13172
|
+
|
|
12792
13173
|
// lib/solvers/InlineNetLabelSolver/InlineNetLabelSolver.ts
|
|
12793
13174
|
var DEFAULT_INLINE_NET_LABEL_HEIGHT = 0.18;
|
|
12794
13175
|
var INLINE_NET_LABEL_TRACE_MARGIN = 0.05;
|
|
@@ -12803,6 +13184,7 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
12803
13184
|
queuedConnections;
|
|
12804
13185
|
tracesByPinPairKey;
|
|
12805
13186
|
hasAlignedPortOnlyStubs = false;
|
|
13187
|
+
postProcessedOutput;
|
|
12806
13188
|
constructor(input) {
|
|
12807
13189
|
super();
|
|
12808
13190
|
this.inputProblem = input.inputProblem;
|
|
@@ -12863,6 +13245,10 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
12863
13245
|
this.hasAlignedPortOnlyStubs = true;
|
|
12864
13246
|
return;
|
|
12865
13247
|
}
|
|
13248
|
+
if (!this.postProcessedOutput) {
|
|
13249
|
+
this.postProcessedOutput = this.buildPostProcessedOutput();
|
|
13250
|
+
return;
|
|
13251
|
+
}
|
|
12866
13252
|
this.solved = true;
|
|
12867
13253
|
this.stats.inlineNetLabelCount = this.inlineNetLabelPlacements.length;
|
|
12868
13254
|
}
|
|
@@ -13109,19 +13495,29 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13109
13495
|
(trace) => !(supersededNetLabelKeys.has(trace.globalConnNetId) && trace.mspPairId.startsWith("available-net-orientation-"))
|
|
13110
13496
|
);
|
|
13111
13497
|
}
|
|
13112
|
-
|
|
13498
|
+
buildPostProcessedOutput() {
|
|
13113
13499
|
const superseded = this.getSupersededNetLabelKeys();
|
|
13500
|
+
const retainedNetLabelPlacements = this.inputNetLabelPlacements.filter(
|
|
13501
|
+
(placement) => !superseded.has(placement.globalConnNetId)
|
|
13502
|
+
);
|
|
13503
|
+
const outputTraces = this.getOutputTraces(superseded);
|
|
13504
|
+
const pushed = pushAnchoredNetLabelsAwayFromInlineLabels({
|
|
13505
|
+
inputProblem: this.inputProblem,
|
|
13506
|
+
traces: outputTraces,
|
|
13507
|
+
netLabelPlacements: retainedNetLabelPlacements,
|
|
13508
|
+
inlineNetLabelPlacements: this.inlineNetLabelPlacements
|
|
13509
|
+
});
|
|
13510
|
+
this.stats.pushedAnchoredNetLabelCount = pushed.movedLabelCount;
|
|
13114
13511
|
return {
|
|
13115
|
-
|
|
13116
|
-
|
|
13117
|
-
// actual net trace, but discard that now-orphaned label connector.
|
|
13118
|
-
traces: this.getOutputTraces(superseded),
|
|
13119
|
-
netLabelPlacements: this.inputNetLabelPlacements.filter(
|
|
13120
|
-
(placement) => !superseded.has(placement.globalConnNetId)
|
|
13121
|
-
),
|
|
13512
|
+
traces: pushed.traces,
|
|
13513
|
+
netLabelPlacements: pushed.netLabelPlacements,
|
|
13122
13514
|
inlineNetLabelPlacements: this.inlineNetLabelPlacements
|
|
13123
13515
|
};
|
|
13124
13516
|
}
|
|
13517
|
+
getOutput() {
|
|
13518
|
+
if (this.postProcessedOutput) return this.postProcessedOutput;
|
|
13519
|
+
return this.buildPostProcessedOutput();
|
|
13520
|
+
}
|
|
13125
13521
|
visualize() {
|
|
13126
13522
|
const graphics = visualizeInputProblem(this.inputProblem);
|
|
13127
13523
|
graphics.lines ??= [];
|