@tscircuit/schematic-trace-solver 0.0.61 → 0.0.63
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 +71 -5
- package/dist/index.js +421 -16
- package/lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts +16 -0
- package/lib/solvers/NetLabelNetLabelCollisionSolver/NetLabelNetLabelCollisionSolver.ts +449 -0
- package/lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver.ts +24 -0
- package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/SingleNetLabelPlacementSolver.ts +7 -1
- package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/geometry.ts +9 -4
- package/lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/solvePortOnlyPin.ts +3 -0
- package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +15 -0
- package/lib/solvers/TraceAnchoredNetLabelOverlapSolver/candidates.ts +19 -0
- package/lib/types/InputProblem.ts +1 -0
- package/package.json +1 -1
- package/site/examples/example39.page.tsx +4 -0
- package/site/examples/example40.page.tsx +4 -0
- package/site/examples/example41.page.tsx +4 -0
- package/tests/assets/example39.json +71 -0
- package/tests/assets/example40.json +157 -0
- package/tests/assets/example41.json +82 -0
- package/tests/examples/__snapshots__/example39.snap.svg +107 -0
- package/tests/examples/__snapshots__/example40.snap.svg +231 -0
- package/tests/examples/__snapshots__/example41.snap.svg +119 -0
- package/tests/examples/example39.test.ts +12 -0
- package/tests/examples/example40.test.ts +12 -0
- package/tests/examples/example41.test.ts +12 -0
package/dist/index.js
CHANGED
|
@@ -1511,18 +1511,19 @@ var ChipObstacleSpatialIndex = class {
|
|
|
1511
1511
|
var NET_LABEL_HORIZONTAL_WIDTH = 0.45;
|
|
1512
1512
|
var NET_LABEL_HORIZONTAL_HEIGHT = 0.2;
|
|
1513
1513
|
function getDimsForOrientation(params) {
|
|
1514
|
-
const { orientation, netLabelWidth } = params;
|
|
1514
|
+
const { orientation, netLabelWidth, netLabelHeight } = params;
|
|
1515
1515
|
const horizWidth = typeof netLabelWidth === "number" ? netLabelWidth : NET_LABEL_HORIZONTAL_WIDTH;
|
|
1516
|
+
const horizHeight = typeof netLabelHeight === "number" ? netLabelHeight : NET_LABEL_HORIZONTAL_HEIGHT;
|
|
1516
1517
|
if (orientation === "y+" || orientation === "y-") {
|
|
1517
1518
|
return {
|
|
1518
|
-
// Rotated,
|
|
1519
|
-
width:
|
|
1519
|
+
// Rotated: horizontal length = netLabelHeight, vertical length = netLabelWidth
|
|
1520
|
+
width: horizHeight,
|
|
1520
1521
|
height: horizWidth
|
|
1521
1522
|
};
|
|
1522
1523
|
}
|
|
1523
1524
|
return {
|
|
1524
1525
|
width: horizWidth,
|
|
1525
|
-
height:
|
|
1526
|
+
height: horizHeight
|
|
1526
1527
|
};
|
|
1527
1528
|
}
|
|
1528
1529
|
function getCenterFromAnchor(anchor, orientation, width, height) {
|
|
@@ -1651,7 +1652,8 @@ function solveNetLabelPlacementForPortOnlyPin(params) {
|
|
|
1651
1652
|
chipObstacleSpatialIndex,
|
|
1652
1653
|
overlappingSameNetTraceGroup,
|
|
1653
1654
|
availableOrientations,
|
|
1654
|
-
netLabelWidth
|
|
1655
|
+
netLabelWidth,
|
|
1656
|
+
netLabelHeight
|
|
1655
1657
|
} = params;
|
|
1656
1658
|
const pinId = overlappingSameNetTraceGroup.portOnlyPinId;
|
|
1657
1659
|
if (!pinId) {
|
|
@@ -1685,7 +1687,8 @@ function solveNetLabelPlacementForPortOnlyPin(params) {
|
|
|
1685
1687
|
for (const orientation of orientations) {
|
|
1686
1688
|
const { width: width2, height: height2 } = getDimsForOrientation({
|
|
1687
1689
|
orientation,
|
|
1688
|
-
netLabelWidth
|
|
1690
|
+
netLabelWidth,
|
|
1691
|
+
netLabelHeight
|
|
1689
1692
|
});
|
|
1690
1693
|
const baseCenter2 = getCenterFromAnchor(anchor, orientation, width2, height2);
|
|
1691
1694
|
const outward2 = outwardOf(orientation);
|
|
@@ -1857,8 +1860,9 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
|
|
|
1857
1860
|
overlappingSameNetTraceGroup;
|
|
1858
1861
|
availableOrientations;
|
|
1859
1862
|
chipObstacleSpatialIndex;
|
|
1860
|
-
// Optional override for the width of the net label (per netId)
|
|
1863
|
+
// Optional override for the width/height of the net label (per netId)
|
|
1861
1864
|
netLabelWidth;
|
|
1865
|
+
netLabelHeight;
|
|
1862
1866
|
netLabelPlacement = null;
|
|
1863
1867
|
testedCandidates = [];
|
|
1864
1868
|
constructor(params) {
|
|
@@ -1868,6 +1872,7 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
|
|
|
1868
1872
|
this.overlappingSameNetTraceGroup = params.overlappingSameNetTraceGroup;
|
|
1869
1873
|
this.availableOrientations = params.availableOrientations;
|
|
1870
1874
|
this.netLabelWidth = params.netLabelWidth;
|
|
1875
|
+
this.netLabelHeight = params.netLabelHeight;
|
|
1871
1876
|
this.chipObstacleSpatialIndex = params.inputProblem._chipObstacleSpatialIndex ?? new ChipObstacleSpatialIndex(params.inputProblem.chips);
|
|
1872
1877
|
}
|
|
1873
1878
|
getConstructorParams() {
|
|
@@ -1876,7 +1881,8 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
|
|
|
1876
1881
|
inputTraceMap: this.inputTraceMap,
|
|
1877
1882
|
overlappingSameNetTraceGroup: this.overlappingSameNetTraceGroup,
|
|
1878
1883
|
availableOrientations: this.availableOrientations,
|
|
1879
|
-
netLabelWidth: this.netLabelWidth
|
|
1884
|
+
netLabelWidth: this.netLabelWidth,
|
|
1885
|
+
netLabelHeight: this.netLabelHeight
|
|
1880
1886
|
};
|
|
1881
1887
|
}
|
|
1882
1888
|
_step() {
|
|
@@ -1891,7 +1897,8 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
|
|
|
1891
1897
|
chipObstacleSpatialIndex: this.chipObstacleSpatialIndex,
|
|
1892
1898
|
overlappingSameNetTraceGroup: this.overlappingSameNetTraceGroup,
|
|
1893
1899
|
availableOrientations: this.availableOrientations,
|
|
1894
|
-
netLabelWidth: this.netLabelWidth
|
|
1900
|
+
netLabelWidth: this.netLabelWidth,
|
|
1901
|
+
netLabelHeight: this.netLabelHeight
|
|
1895
1902
|
});
|
|
1896
1903
|
this.testedCandidates.push(...res.testedCandidates);
|
|
1897
1904
|
if (res.placement) {
|
|
@@ -1961,7 +1968,8 @@ var SingleNetLabelPlacementSolver = class extends BaseSolver {
|
|
|
1961
1968
|
for (const orientation of candidateOrients) {
|
|
1962
1969
|
const { width, height } = getDimsForOrientation({
|
|
1963
1970
|
orientation,
|
|
1964
|
-
netLabelWidth: this.netLabelWidth
|
|
1971
|
+
netLabelWidth: this.netLabelWidth,
|
|
1972
|
+
netLabelHeight: this.netLabelHeight
|
|
1965
1973
|
});
|
|
1966
1974
|
const center = getCenterFromAnchor(
|
|
1967
1975
|
anchor,
|
|
@@ -2250,6 +2258,21 @@ var NetLabelPlacementSolver = class extends BaseSolver {
|
|
|
2250
2258
|
(nc) => nc.pinIds.some((pid) => pinIds.includes(pid))
|
|
2251
2259
|
)?.netLabelWidth;
|
|
2252
2260
|
}
|
|
2261
|
+
getNetLabelHeightForGroup(group) {
|
|
2262
|
+
if (group.netId) {
|
|
2263
|
+
const ncHeight = this.inputProblem.netConnections.find(
|
|
2264
|
+
(nc) => nc.netId === group.netId
|
|
2265
|
+
)?.netLabelHeight;
|
|
2266
|
+
if (ncHeight !== void 0) return ncHeight;
|
|
2267
|
+
}
|
|
2268
|
+
const pinIds = group.overlappingTraces?.pins.map((p) => p.pinId) ?? [];
|
|
2269
|
+
if (group.portOnlyPinId) {
|
|
2270
|
+
pinIds.push(group.portOnlyPinId);
|
|
2271
|
+
}
|
|
2272
|
+
return this.inputProblem.netConnections.find(
|
|
2273
|
+
(nc) => nc.pinIds.some((pid) => pinIds.includes(pid))
|
|
2274
|
+
)?.netLabelHeight;
|
|
2275
|
+
}
|
|
2253
2276
|
_step() {
|
|
2254
2277
|
if (this.activeSubSolver?.solved) {
|
|
2255
2278
|
this.netLabelPlacements.push(this.activeSubSolver.netLabelPlacement);
|
|
@@ -2265,12 +2288,14 @@ var NetLabelPlacementSolver = class extends BaseSolver {
|
|
|
2265
2288
|
if (!this.triedAnyOrientationFallbackForCurrentGroup && !isAlreadyFull && this.currentGroup) {
|
|
2266
2289
|
this.triedAnyOrientationFallbackForCurrentGroup = true;
|
|
2267
2290
|
const netLabelWidth2 = this.getNetLabelWidthForGroup(this.currentGroup);
|
|
2291
|
+
const netLabelHeight2 = this.getNetLabelHeightForGroup(this.currentGroup);
|
|
2268
2292
|
this.activeSubSolver = new SingleNetLabelPlacementSolver({
|
|
2269
2293
|
inputProblem: this.inputProblem,
|
|
2270
2294
|
inputTraceMap: this.inputTraceMap,
|
|
2271
2295
|
overlappingSameNetTraceGroup: this.currentGroup,
|
|
2272
2296
|
availableOrientations: fullOrients,
|
|
2273
|
-
netLabelWidth: netLabelWidth2
|
|
2297
|
+
netLabelWidth: netLabelWidth2,
|
|
2298
|
+
netLabelHeight: netLabelHeight2
|
|
2274
2299
|
});
|
|
2275
2300
|
return;
|
|
2276
2301
|
}
|
|
@@ -2291,12 +2316,14 @@ var NetLabelPlacementSolver = class extends BaseSolver {
|
|
|
2291
2316
|
this.currentGroup = nextOverlappingSameNetTraceGroup;
|
|
2292
2317
|
this.triedAnyOrientationFallbackForCurrentGroup = false;
|
|
2293
2318
|
const netLabelWidth = this.getNetLabelWidthForGroup(this.currentGroup);
|
|
2319
|
+
const netLabelHeight = this.getNetLabelHeightForGroup(this.currentGroup);
|
|
2294
2320
|
this.activeSubSolver = new SingleNetLabelPlacementSolver({
|
|
2295
2321
|
inputProblem: this.inputProblem,
|
|
2296
2322
|
inputTraceMap: this.inputTraceMap,
|
|
2297
2323
|
overlappingSameNetTraceGroup: nextOverlappingSameNetTraceGroup,
|
|
2298
2324
|
availableOrientations: this.inputProblem.availableNetLabelOrientations[netId] ?? ["x+", "x-", "y+", "y-"],
|
|
2299
|
-
netLabelWidth
|
|
2325
|
+
netLabelWidth,
|
|
2326
|
+
netLabelHeight
|
|
2300
2327
|
});
|
|
2301
2328
|
}
|
|
2302
2329
|
visualize() {
|
|
@@ -6084,7 +6111,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6084
6111
|
const anchorPoint = this.getWickOffsetAnchor(label.anchorPoint, orientation);
|
|
6085
6112
|
const { width, height } = getDimsForOrientation({
|
|
6086
6113
|
orientation,
|
|
6087
|
-
netLabelWidth: this.getNetLabelWidth(label)
|
|
6114
|
+
netLabelWidth: this.getNetLabelWidth(label),
|
|
6115
|
+
netLabelHeight: this.getNetLabelHeight(label)
|
|
6088
6116
|
});
|
|
6089
6117
|
return this.getSideOffsetAnchor({
|
|
6090
6118
|
anchorPoint,
|
|
@@ -6133,7 +6161,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6133
6161
|
getSearchDistanceLimit(label, orientation) {
|
|
6134
6162
|
const { width, height } = getDimsForOrientation({
|
|
6135
6163
|
orientation,
|
|
6136
|
-
netLabelWidth: this.getNetLabelWidth(label)
|
|
6164
|
+
netLabelWidth: this.getNetLabelWidth(label),
|
|
6165
|
+
netLabelHeight: this.getNetLabelHeight(label)
|
|
6137
6166
|
});
|
|
6138
6167
|
const labelLength = orientation === "y+" || orientation === "y-" ? height : width;
|
|
6139
6168
|
return Math.min(this.maxSearchDistance, labelLength * 2);
|
|
@@ -6156,7 +6185,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6156
6185
|
createCandidate(label, anchorPoint, orientation) {
|
|
6157
6186
|
const { width, height } = getDimsForOrientation({
|
|
6158
6187
|
orientation,
|
|
6159
|
-
netLabelWidth: this.getNetLabelWidth(label)
|
|
6188
|
+
netLabelWidth: this.getNetLabelWidth(label),
|
|
6189
|
+
netLabelHeight: this.getNetLabelHeight(label)
|
|
6160
6190
|
});
|
|
6161
6191
|
return {
|
|
6162
6192
|
orientation,
|
|
@@ -6185,6 +6215,17 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6185
6215
|
(nc) => nc.pinIds.some((pid) => label.pinIds.includes(pid))
|
|
6186
6216
|
)?.netLabelWidth;
|
|
6187
6217
|
}
|
|
6218
|
+
getNetLabelHeight(label) {
|
|
6219
|
+
if (label.netId) {
|
|
6220
|
+
const ncHeight = this.inputProblem.netConnections.find(
|
|
6221
|
+
(connection) => connection.netId === label.netId
|
|
6222
|
+
)?.netLabelHeight;
|
|
6223
|
+
if (ncHeight !== void 0) return ncHeight;
|
|
6224
|
+
}
|
|
6225
|
+
return this.inputProblem.netConnections.find(
|
|
6226
|
+
(nc) => nc.pinIds.some((pid) => label.pinIds.includes(pid))
|
|
6227
|
+
)?.netLabelHeight;
|
|
6228
|
+
}
|
|
6188
6229
|
getCandidateStatus(candidate, label, labelIndex) {
|
|
6189
6230
|
const boundsStatus = this.getBoundsStatus(
|
|
6190
6231
|
getRectBounds(candidate.center, candidate.width, candidate.height),
|
|
@@ -6798,6 +6839,7 @@ var generateCandidatesAlongTrace = (params) => {
|
|
|
6798
6839
|
getTraceVertexDistances(traceLocation.trace)
|
|
6799
6840
|
);
|
|
6800
6841
|
const netLabelWidth = getNetLabelWidth(inputProblem, label);
|
|
6842
|
+
const netLabelHeight = getNetLabelHeight(inputProblem, label);
|
|
6801
6843
|
const candidates = [];
|
|
6802
6844
|
const seenCandidateKeys = /* @__PURE__ */ new Set();
|
|
6803
6845
|
for (const pathDistance of candidateDistances) {
|
|
@@ -6820,6 +6862,7 @@ var generateCandidatesAlongTrace = (params) => {
|
|
|
6820
6862
|
point,
|
|
6821
6863
|
orientation,
|
|
6822
6864
|
netLabelWidth,
|
|
6865
|
+
netLabelHeight,
|
|
6823
6866
|
traceLocation,
|
|
6824
6867
|
pathDistance,
|
|
6825
6868
|
label
|
|
@@ -6857,13 +6900,15 @@ var createCandidate = (params) => {
|
|
|
6857
6900
|
point,
|
|
6858
6901
|
orientation,
|
|
6859
6902
|
netLabelWidth,
|
|
6903
|
+
netLabelHeight,
|
|
6860
6904
|
traceLocation,
|
|
6861
6905
|
pathDistance,
|
|
6862
6906
|
label
|
|
6863
6907
|
} = params;
|
|
6864
6908
|
const { width, height } = getDimsForOrientation({
|
|
6865
6909
|
orientation,
|
|
6866
|
-
netLabelWidth
|
|
6910
|
+
netLabelWidth,
|
|
6911
|
+
netLabelHeight
|
|
6867
6912
|
});
|
|
6868
6913
|
return {
|
|
6869
6914
|
anchorPoint: point,
|
|
@@ -7026,6 +7071,15 @@ var getNetLabelWidth = (inputProblem, label) => {
|
|
|
7026
7071
|
}
|
|
7027
7072
|
return label.width;
|
|
7028
7073
|
};
|
|
7074
|
+
var getNetLabelHeight = (inputProblem, label) => {
|
|
7075
|
+
const ncHeightByNetId = inputProblem.netConnections.find(
|
|
7076
|
+
(connection) => connection.netId === label.netId
|
|
7077
|
+
)?.netLabelHeight;
|
|
7078
|
+
if (ncHeightByNetId !== void 0) return ncHeightByNetId;
|
|
7079
|
+
return inputProblem.netConnections.find(
|
|
7080
|
+
(nc) => nc.pinIds.some((pid) => label.pinIds.includes(pid))
|
|
7081
|
+
)?.netLabelHeight;
|
|
7082
|
+
};
|
|
7029
7083
|
var roundDistance = (distance3) => Number(distance3.toFixed(6));
|
|
7030
7084
|
var dedupeOrientations = (orientations) => [
|
|
7031
7085
|
...new Set(orientations)
|
|
@@ -7605,6 +7659,345 @@ globalConnNetId: ${label.globalConnNetId}`
|
|
|
7605
7659
|
}
|
|
7606
7660
|
};
|
|
7607
7661
|
|
|
7662
|
+
// lib/solvers/NetLabelNetLabelCollisionSolver/NetLabelNetLabelCollisionSolver.ts
|
|
7663
|
+
var ANCHOR_TRACE_CLEARANCE = 1e-4;
|
|
7664
|
+
var SEGMENT_PARALLEL_EPS = 1e-6;
|
|
7665
|
+
var CANDIDATE_STEP2 = 0.1;
|
|
7666
|
+
var OUTWARD_DIR = {
|
|
7667
|
+
"x+": { x: 1, y: 0 },
|
|
7668
|
+
"x-": { x: -1, y: 0 },
|
|
7669
|
+
"y+": { x: 0, y: 1 },
|
|
7670
|
+
"y-": { x: 0, y: -1 }
|
|
7671
|
+
};
|
|
7672
|
+
var CANDIDATE_STATUS_COLOR = {
|
|
7673
|
+
ok: "green",
|
|
7674
|
+
"label-collision": "orange",
|
|
7675
|
+
"trace-collision": "darkorange",
|
|
7676
|
+
"chip-collision": "red"
|
|
7677
|
+
};
|
|
7678
|
+
var CANDIDATE_STATUS_FILL = {
|
|
7679
|
+
ok: "rgba(0, 200, 0, 0.25)",
|
|
7680
|
+
"label-collision": "rgba(255, 160, 0, 0.2)",
|
|
7681
|
+
"trace-collision": "rgba(200, 80, 0, 0.2)",
|
|
7682
|
+
"chip-collision": "rgba(220, 0, 0, 0.15)"
|
|
7683
|
+
};
|
|
7684
|
+
function boundsOverlap(a, b) {
|
|
7685
|
+
return a.minX < b.maxX - 1e-9 && a.maxX > b.minX + 1e-9 && a.minY < b.maxY - 1e-9 && a.maxY > b.minY + 1e-9;
|
|
7686
|
+
}
|
|
7687
|
+
function sampleAnchorsAlongSegment(a, b) {
|
|
7688
|
+
const dx = b.x - a.x;
|
|
7689
|
+
const dy = b.y - a.y;
|
|
7690
|
+
const len = Math.sqrt(dx * dx + dy * dy);
|
|
7691
|
+
const steps = Math.max(1, Math.round(len / CANDIDATE_STEP2));
|
|
7692
|
+
const anchors = [];
|
|
7693
|
+
for (let k = 0; k <= steps; k++) {
|
|
7694
|
+
const t = k / steps;
|
|
7695
|
+
anchors.push({ x: a.x + t * dx, y: a.y + t * dy });
|
|
7696
|
+
}
|
|
7697
|
+
return anchors;
|
|
7698
|
+
}
|
|
7699
|
+
var NetLabelNetLabelCollisionSolver = class extends BaseSolver {
|
|
7700
|
+
inputProblem;
|
|
7701
|
+
traces;
|
|
7702
|
+
netLabelPlacements;
|
|
7703
|
+
outputNetLabelPlacements;
|
|
7704
|
+
currentCollision = null;
|
|
7705
|
+
currentLabelToMove = null;
|
|
7706
|
+
candidateResults = [];
|
|
7707
|
+
chipIndex;
|
|
7708
|
+
traceMap;
|
|
7709
|
+
skippedCollisionKeys = /* @__PURE__ */ new Set();
|
|
7710
|
+
labelsToTry = [];
|
|
7711
|
+
candidateQueue = [];
|
|
7712
|
+
candidateIndex = 0;
|
|
7713
|
+
constructor(params) {
|
|
7714
|
+
super();
|
|
7715
|
+
this.inputProblem = params.inputProblem;
|
|
7716
|
+
this.traces = params.traces;
|
|
7717
|
+
this.netLabelPlacements = params.netLabelPlacements;
|
|
7718
|
+
this.outputNetLabelPlacements = [...params.netLabelPlacements];
|
|
7719
|
+
this.chipIndex = params.inputProblem._chipObstacleSpatialIndex ?? new ChipObstacleSpatialIndex(params.inputProblem.chips);
|
|
7720
|
+
this.traceMap = Object.fromEntries(
|
|
7721
|
+
params.traces.map((t) => [t.mspPairId, t])
|
|
7722
|
+
);
|
|
7723
|
+
}
|
|
7724
|
+
getConstructorParams() {
|
|
7725
|
+
return {
|
|
7726
|
+
inputProblem: this.inputProblem,
|
|
7727
|
+
traces: this.traces,
|
|
7728
|
+
netLabelPlacements: this.netLabelPlacements
|
|
7729
|
+
};
|
|
7730
|
+
}
|
|
7731
|
+
getOutput() {
|
|
7732
|
+
return { netLabelPlacements: this.outputNetLabelPlacements };
|
|
7733
|
+
}
|
|
7734
|
+
labelBounds(label) {
|
|
7735
|
+
return getRectBounds(label.center, label.width, label.height);
|
|
7736
|
+
}
|
|
7737
|
+
collisionKey(a, b) {
|
|
7738
|
+
return [a.globalConnNetId, b.globalConnNetId].sort().join("::");
|
|
7739
|
+
}
|
|
7740
|
+
findNextCollidingPair() {
|
|
7741
|
+
const labels = this.outputNetLabelPlacements;
|
|
7742
|
+
for (let i = 0; i < labels.length; i++) {
|
|
7743
|
+
for (let j = i + 1; j < labels.length; j++) {
|
|
7744
|
+
const a = labels[i];
|
|
7745
|
+
const b = labels[j];
|
|
7746
|
+
if (a.globalConnNetId === b.globalConnNetId) continue;
|
|
7747
|
+
if (this.skippedCollisionKeys.has(this.collisionKey(a, b))) continue;
|
|
7748
|
+
if (boundsOverlap(this.labelBounds(a), this.labelBounds(b)))
|
|
7749
|
+
return [a, b];
|
|
7750
|
+
}
|
|
7751
|
+
}
|
|
7752
|
+
return null;
|
|
7753
|
+
}
|
|
7754
|
+
netLabelWidthOf(label) {
|
|
7755
|
+
if (label.orientation === "x+" || label.orientation === "x-")
|
|
7756
|
+
return label.width;
|
|
7757
|
+
return label.height;
|
|
7758
|
+
}
|
|
7759
|
+
netLabelHeightOf(label) {
|
|
7760
|
+
if (label.orientation === "x+" || label.orientation === "x-")
|
|
7761
|
+
return label.height;
|
|
7762
|
+
return label.width;
|
|
7763
|
+
}
|
|
7764
|
+
buildCandidatesForLabel(label) {
|
|
7765
|
+
const netLabelWidth = this.netLabelWidthOf(label);
|
|
7766
|
+
const netLabelHeight = this.netLabelHeightOf(label);
|
|
7767
|
+
const candidates = [];
|
|
7768
|
+
const buildCandidate = (orientation, anchor, hostPairId, hostSegIndex) => {
|
|
7769
|
+
const { width, height } = getDimsForOrientation({
|
|
7770
|
+
orientation,
|
|
7771
|
+
netLabelWidth,
|
|
7772
|
+
netLabelHeight
|
|
7773
|
+
});
|
|
7774
|
+
const baseCenter = getCenterFromAnchor(anchor, orientation, width, height);
|
|
7775
|
+
const outwardDir = OUTWARD_DIR[orientation];
|
|
7776
|
+
const center = {
|
|
7777
|
+
x: baseCenter.x + outwardDir.x * ANCHOR_TRACE_CLEARANCE,
|
|
7778
|
+
y: baseCenter.y + outwardDir.y * ANCHOR_TRACE_CLEARANCE
|
|
7779
|
+
};
|
|
7780
|
+
return {
|
|
7781
|
+
orientation,
|
|
7782
|
+
anchor,
|
|
7783
|
+
center,
|
|
7784
|
+
width,
|
|
7785
|
+
height,
|
|
7786
|
+
bounds: getRectBounds(center, width, height),
|
|
7787
|
+
hostPairId,
|
|
7788
|
+
hostSegIndex,
|
|
7789
|
+
status: null
|
|
7790
|
+
};
|
|
7791
|
+
};
|
|
7792
|
+
const isPortOnly = label.mspConnectionPairIds.length === 0;
|
|
7793
|
+
if (isPortOnly) {
|
|
7794
|
+
const allOrientations = ["x+", "x-", "y+", "y-"];
|
|
7795
|
+
const orderedOrientations = [
|
|
7796
|
+
label.orientation,
|
|
7797
|
+
...allOrientations.filter((o) => o !== label.orientation)
|
|
7798
|
+
];
|
|
7799
|
+
for (const orientation of orderedOrientations) {
|
|
7800
|
+
candidates.push(buildCandidate(orientation, label.anchorPoint));
|
|
7801
|
+
}
|
|
7802
|
+
} else {
|
|
7803
|
+
for (const mspPairId of label.mspConnectionPairIds) {
|
|
7804
|
+
const trace = this.traceMap[mspPairId];
|
|
7805
|
+
if (!trace) continue;
|
|
7806
|
+
const pts = trace.tracePath;
|
|
7807
|
+
for (let si = 0; si < pts.length - 1; si++) {
|
|
7808
|
+
const segStart = pts[si];
|
|
7809
|
+
const segEnd = pts[si + 1];
|
|
7810
|
+
const isHorizontal3 = Math.abs(segStart.y - segEnd.y) < SEGMENT_PARALLEL_EPS;
|
|
7811
|
+
const isVertical4 = Math.abs(segStart.x - segEnd.x) < SEGMENT_PARALLEL_EPS;
|
|
7812
|
+
if (!isHorizontal3 && !isVertical4) continue;
|
|
7813
|
+
let perpendicularOrientations;
|
|
7814
|
+
if (isHorizontal3) {
|
|
7815
|
+
perpendicularOrientations = ["y+", "y-"];
|
|
7816
|
+
} else {
|
|
7817
|
+
perpendicularOrientations = ["x+", "x-"];
|
|
7818
|
+
}
|
|
7819
|
+
for (const anchor of sampleAnchorsAlongSegment(segStart, segEnd)) {
|
|
7820
|
+
for (const orientation of perpendicularOrientations) {
|
|
7821
|
+
candidates.push(
|
|
7822
|
+
buildCandidate(
|
|
7823
|
+
orientation,
|
|
7824
|
+
anchor,
|
|
7825
|
+
mspPairId,
|
|
7826
|
+
si
|
|
7827
|
+
)
|
|
7828
|
+
);
|
|
7829
|
+
}
|
|
7830
|
+
}
|
|
7831
|
+
}
|
|
7832
|
+
}
|
|
7833
|
+
}
|
|
7834
|
+
return candidates;
|
|
7835
|
+
}
|
|
7836
|
+
checkCandidate(candidate, movingLabelNetId, obstacleLabels) {
|
|
7837
|
+
const { bounds, hostPairId, hostSegIndex } = candidate;
|
|
7838
|
+
if (this.chipIndex.getChipsInBounds(bounds).length > 0)
|
|
7839
|
+
return "chip-collision";
|
|
7840
|
+
if (rectIntersectsAnyTrace(bounds, this.traceMap, hostPairId, hostSegIndex).hasIntersection) {
|
|
7841
|
+
return "trace-collision";
|
|
7842
|
+
}
|
|
7843
|
+
for (const obstacle of obstacleLabels) {
|
|
7844
|
+
if (obstacle.globalConnNetId === movingLabelNetId) continue;
|
|
7845
|
+
if (boundsOverlap(bounds, this.labelBounds(obstacle)))
|
|
7846
|
+
return "label-collision";
|
|
7847
|
+
}
|
|
7848
|
+
return "ok";
|
|
7849
|
+
}
|
|
7850
|
+
beginSearchForLabel(label) {
|
|
7851
|
+
this.currentLabelToMove = label;
|
|
7852
|
+
this.candidateQueue = this.buildCandidatesForLabel(label);
|
|
7853
|
+
this.candidateIndex = 0;
|
|
7854
|
+
this.candidateResults = [];
|
|
7855
|
+
}
|
|
7856
|
+
clearActiveSearch() {
|
|
7857
|
+
this.currentCollision = null;
|
|
7858
|
+
this.currentLabelToMove = null;
|
|
7859
|
+
this.labelsToTry = [];
|
|
7860
|
+
this.candidateQueue = [];
|
|
7861
|
+
this.candidateIndex = 0;
|
|
7862
|
+
this.candidateResults = [];
|
|
7863
|
+
}
|
|
7864
|
+
_step() {
|
|
7865
|
+
if (!this.currentCollision) {
|
|
7866
|
+
const pair = this.findNextCollidingPair();
|
|
7867
|
+
if (!pair) {
|
|
7868
|
+
this.solved = true;
|
|
7869
|
+
return;
|
|
7870
|
+
}
|
|
7871
|
+
this.currentCollision = pair;
|
|
7872
|
+
this.labelsToTry = [pair[1], pair[0]];
|
|
7873
|
+
this.beginSearchForLabel(this.labelsToTry.shift());
|
|
7874
|
+
return;
|
|
7875
|
+
}
|
|
7876
|
+
if (this.candidateIndex >= this.candidateQueue.length) {
|
|
7877
|
+
if (this.labelsToTry.length > 0) {
|
|
7878
|
+
this.beginSearchForLabel(this.labelsToTry.shift());
|
|
7879
|
+
} else {
|
|
7880
|
+
this.skippedCollisionKeys.add(
|
|
7881
|
+
this.collisionKey(this.currentCollision[0], this.currentCollision[1])
|
|
7882
|
+
);
|
|
7883
|
+
this.clearActiveSearch();
|
|
7884
|
+
}
|
|
7885
|
+
return;
|
|
7886
|
+
}
|
|
7887
|
+
const candidate = this.candidateQueue[this.candidateIndex++];
|
|
7888
|
+
const [labelA, labelB] = this.currentCollision;
|
|
7889
|
+
let fixedLabel;
|
|
7890
|
+
if (this.currentLabelToMove === labelB) {
|
|
7891
|
+
fixedLabel = labelA;
|
|
7892
|
+
} else {
|
|
7893
|
+
fixedLabel = labelB;
|
|
7894
|
+
}
|
|
7895
|
+
const obstacleLabels = [
|
|
7896
|
+
...this.outputNetLabelPlacements.filter(
|
|
7897
|
+
(l) => l !== labelA && l !== labelB
|
|
7898
|
+
),
|
|
7899
|
+
fixedLabel
|
|
7900
|
+
];
|
|
7901
|
+
const status = this.checkCandidate(
|
|
7902
|
+
candidate,
|
|
7903
|
+
this.currentLabelToMove.globalConnNetId,
|
|
7904
|
+
obstacleLabels
|
|
7905
|
+
);
|
|
7906
|
+
candidate.status = status;
|
|
7907
|
+
this.candidateResults.push({ ...candidate });
|
|
7908
|
+
if (status === "ok") {
|
|
7909
|
+
const idx = this.outputNetLabelPlacements.indexOf(
|
|
7910
|
+
this.currentLabelToMove
|
|
7911
|
+
);
|
|
7912
|
+
if (idx !== -1) {
|
|
7913
|
+
this.outputNetLabelPlacements[idx] = {
|
|
7914
|
+
...this.currentLabelToMove,
|
|
7915
|
+
orientation: candidate.orientation,
|
|
7916
|
+
anchorPoint: candidate.anchor,
|
|
7917
|
+
width: candidate.width,
|
|
7918
|
+
height: candidate.height,
|
|
7919
|
+
center: candidate.center
|
|
7920
|
+
};
|
|
7921
|
+
}
|
|
7922
|
+
this.clearActiveSearch();
|
|
7923
|
+
}
|
|
7924
|
+
}
|
|
7925
|
+
visualize() {
|
|
7926
|
+
const graphics = visualizeInputProblem(this.inputProblem);
|
|
7927
|
+
if (!graphics.lines) graphics.lines = [];
|
|
7928
|
+
if (!graphics.rects) graphics.rects = [];
|
|
7929
|
+
if (!graphics.points) graphics.points = [];
|
|
7930
|
+
for (const trace of this.traces) {
|
|
7931
|
+
graphics.lines.push({
|
|
7932
|
+
points: trace.tracePath,
|
|
7933
|
+
strokeColor: "purple"
|
|
7934
|
+
});
|
|
7935
|
+
}
|
|
7936
|
+
for (const label of this.outputNetLabelPlacements) {
|
|
7937
|
+
const isInActiveCollision = this.currentCollision != null && (label === this.currentCollision[0] || label === this.currentCollision[1]);
|
|
7938
|
+
let labelFill;
|
|
7939
|
+
let labelStroke;
|
|
7940
|
+
let labelText;
|
|
7941
|
+
let pointColor;
|
|
7942
|
+
if (isInActiveCollision) {
|
|
7943
|
+
labelFill = "rgba(255, 0, 0, 0.2)";
|
|
7944
|
+
labelStroke = "red";
|
|
7945
|
+
labelText = `netId: ${label.netId}
|
|
7946
|
+
globalConnNetId: ${label.globalConnNetId}
|
|
7947
|
+
\u26A0 COLLIDING`;
|
|
7948
|
+
pointColor = "red";
|
|
7949
|
+
} else {
|
|
7950
|
+
labelFill = getColorFromString(label.globalConnNetId, 0.35);
|
|
7951
|
+
labelStroke = getColorFromString(label.globalConnNetId, 0.9);
|
|
7952
|
+
labelText = `netId: ${label.netId}
|
|
7953
|
+
globalConnNetId: ${label.globalConnNetId}`;
|
|
7954
|
+
pointColor = getColorFromString(label.globalConnNetId, 0.9);
|
|
7955
|
+
}
|
|
7956
|
+
graphics.rects.push({
|
|
7957
|
+
center: label.center,
|
|
7958
|
+
width: label.width,
|
|
7959
|
+
height: label.height,
|
|
7960
|
+
fill: labelFill,
|
|
7961
|
+
strokeColor: labelStroke,
|
|
7962
|
+
label: labelText
|
|
7963
|
+
});
|
|
7964
|
+
graphics.points.push({
|
|
7965
|
+
x: label.anchorPoint.x,
|
|
7966
|
+
y: label.anchorPoint.y,
|
|
7967
|
+
color: pointColor,
|
|
7968
|
+
label: `anchorPoint
|
|
7969
|
+
orientation: ${label.orientation}`
|
|
7970
|
+
});
|
|
7971
|
+
}
|
|
7972
|
+
const movingNetId = this.currentLabelToMove ? this.currentLabelToMove.netId : "?";
|
|
7973
|
+
for (const c of this.candidateResults) {
|
|
7974
|
+
const statusColor = CANDIDATE_STATUS_COLOR[c.status];
|
|
7975
|
+
const statusFill = CANDIDATE_STATUS_FILL[c.status];
|
|
7976
|
+
let strokeDash;
|
|
7977
|
+
if (c.status !== "ok") strokeDash = "4 2";
|
|
7978
|
+
graphics.rects.push({
|
|
7979
|
+
center: c.center,
|
|
7980
|
+
width: c.width,
|
|
7981
|
+
height: c.height,
|
|
7982
|
+
fill: statusFill,
|
|
7983
|
+
strokeColor: statusColor,
|
|
7984
|
+
strokeDash,
|
|
7985
|
+
label: `candidate: ${c.status}
|
|
7986
|
+
orientation: ${c.orientation}
|
|
7987
|
+
moving: ${movingNetId}`
|
|
7988
|
+
});
|
|
7989
|
+
graphics.points.push({
|
|
7990
|
+
x: c.anchor.x,
|
|
7991
|
+
y: c.anchor.y,
|
|
7992
|
+
color: statusColor,
|
|
7993
|
+
label: `candidate anchor
|
|
7994
|
+
${c.status}`
|
|
7995
|
+
});
|
|
7996
|
+
}
|
|
7997
|
+
return graphics;
|
|
7998
|
+
}
|
|
7999
|
+
};
|
|
8000
|
+
|
|
7608
8001
|
// lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts
|
|
7609
8002
|
function definePipelineStep(solverName, solverClass, getConstructorParams, opts = {}) {
|
|
7610
8003
|
return {
|
|
@@ -7630,6 +8023,7 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
7630
8023
|
vccNetLabelCornerPlacementSolver;
|
|
7631
8024
|
traceAnchoredNetLabelOverlapSolver;
|
|
7632
8025
|
netLabelTraceCollisionSolver;
|
|
8026
|
+
netLabelNetLabelCollisionSolver;
|
|
7633
8027
|
startTimeOfPhase;
|
|
7634
8028
|
endTimeOfPhase;
|
|
7635
8029
|
timeSpentOnPhase;
|
|
@@ -7821,6 +8215,17 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
7821
8215
|
netLabelPlacements: instance.traceAnchoredNetLabelOverlapSolver.outputNetLabelPlacements
|
|
7822
8216
|
}
|
|
7823
8217
|
]
|
|
8218
|
+
),
|
|
8219
|
+
definePipelineStep(
|
|
8220
|
+
"netLabelNetLabelCollisionSolver",
|
|
8221
|
+
NetLabelNetLabelCollisionSolver,
|
|
8222
|
+
(instance) => [
|
|
8223
|
+
{
|
|
8224
|
+
inputProblem: instance.inputProblem,
|
|
8225
|
+
traces: instance.netLabelTraceCollisionSolver.getOutput().traces,
|
|
8226
|
+
netLabelPlacements: instance.netLabelTraceCollisionSolver.getOutput().netLabelPlacements
|
|
8227
|
+
}
|
|
8228
|
+
]
|
|
7824
8229
|
)
|
|
7825
8230
|
];
|
|
7826
8231
|
constructor(inputProblem) {
|
|
@@ -429,6 +429,7 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
429
429
|
const { width, height } = getDimsForOrientation({
|
|
430
430
|
orientation,
|
|
431
431
|
netLabelWidth: this.getNetLabelWidth(label),
|
|
432
|
+
netLabelHeight: this.getNetLabelHeight(label),
|
|
432
433
|
})
|
|
433
434
|
|
|
434
435
|
return this.getSideOffsetAnchor({
|
|
@@ -494,6 +495,7 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
494
495
|
const { width, height } = getDimsForOrientation({
|
|
495
496
|
orientation,
|
|
496
497
|
netLabelWidth: this.getNetLabelWidth(label),
|
|
498
|
+
netLabelHeight: this.getNetLabelHeight(label),
|
|
497
499
|
})
|
|
498
500
|
const labelLength =
|
|
499
501
|
orientation === "y+" || orientation === "y-" ? height : width
|
|
@@ -534,6 +536,7 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
534
536
|
const { width, height } = getDimsForOrientation({
|
|
535
537
|
orientation,
|
|
536
538
|
netLabelWidth: this.getNetLabelWidth(label),
|
|
539
|
+
netLabelHeight: this.getNetLabelHeight(label),
|
|
537
540
|
})
|
|
538
541
|
return {
|
|
539
542
|
orientation,
|
|
@@ -567,6 +570,19 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
567
570
|
)?.netLabelWidth
|
|
568
571
|
}
|
|
569
572
|
|
|
573
|
+
private getNetLabelHeight(label: NetLabelPlacement) {
|
|
574
|
+
if (label.netId) {
|
|
575
|
+
const ncHeight = this.inputProblem.netConnections.find(
|
|
576
|
+
(connection) => connection.netId === label.netId,
|
|
577
|
+
)?.netLabelHeight
|
|
578
|
+
if (ncHeight !== undefined) return ncHeight
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
return this.inputProblem.netConnections.find((nc) =>
|
|
582
|
+
nc.pinIds.some((pid) => label.pinIds.includes(pid)),
|
|
583
|
+
)?.netLabelHeight
|
|
584
|
+
}
|
|
585
|
+
|
|
570
586
|
private getCandidateStatus(
|
|
571
587
|
candidate: CandidateLabel,
|
|
572
588
|
label: NetLabelPlacement,
|