@tscircuit/schematic-trace-solver 0.0.62 → 0.0.64
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 +7 -0
- package/dist/index.js +126 -52
- package/lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts +67 -36
- package/lib/solvers/AvailableNetOrientationSolver/geometry.ts +13 -0
- package/lib/solvers/NetLabelNetLabelCollisionSolver/NetLabelNetLabelCollisionSolver.ts +8 -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/NetLabelTraceCollisionSolver/NetLabelTraceCollisionSolver.ts +9 -13
- package/lib/solvers/TraceAnchoredNetLabelOverlapSolver/candidates.ts +19 -0
- package/lib/types/InputProblem.ts +1 -0
- package/package.json +1 -1
- package/tests/assets/example41.json +2 -1
- package/tests/examples/__snapshots__/example34.snap.svg +23 -19
- package/tests/examples/__snapshots__/example41.snap.svg +2 -2
- package/tests/examples/example34.test.ts +8 -0
- package/tests/fixtures/traceLabelCollisions.ts +42 -0
- package/tests/repros/__snapshots__/netlabel-connector-through-rail-label.snap.svg +273 -0
- package/tests/repros/__snapshots__/trace-overlap-box-resistor.snap.svg +113 -0
- package/tests/repros/assets/repro-netlabel-connector-through-label.input.json +139 -0
- package/tests/repros/assets/repro126-trace-overlap-box-resistor.input.json +74 -0
- package/tests/repros/netlabel-connector-through-rail-label.test.ts +19 -0
- package/tests/repros/trace-overlap-box-resistor.test.ts +14 -0
package/dist/index.d.ts
CHANGED
|
@@ -83,6 +83,7 @@ interface InputNetConnection {
|
|
|
83
83
|
netId: string;
|
|
84
84
|
pinIds: Array<PinId>;
|
|
85
85
|
netLabelWidth?: number;
|
|
86
|
+
netLabelHeight?: number;
|
|
86
87
|
}
|
|
87
88
|
interface InputProblem {
|
|
88
89
|
chips: Array<InputChip>;
|
|
@@ -288,6 +289,7 @@ declare class SingleNetLabelPlacementSolver extends BaseSolver {
|
|
|
288
289
|
availableOrientations: Array<FacingDirection>;
|
|
289
290
|
chipObstacleSpatialIndex: ChipObstacleSpatialIndex;
|
|
290
291
|
netLabelWidth?: number;
|
|
292
|
+
netLabelHeight?: number;
|
|
291
293
|
netLabelPlacement: NetLabelPlacement | null;
|
|
292
294
|
testedCandidates: Array<{
|
|
293
295
|
center: {
|
|
@@ -316,6 +318,7 @@ declare class SingleNetLabelPlacementSolver extends BaseSolver {
|
|
|
316
318
|
overlappingSameNetTraceGroup: OverlappingSameNetTraceGroup;
|
|
317
319
|
availableOrientations: FacingDirection[];
|
|
318
320
|
netLabelWidth?: number;
|
|
321
|
+
netLabelHeight?: number;
|
|
319
322
|
});
|
|
320
323
|
getConstructorParams(): ConstructorParameters<typeof SingleNetLabelPlacementSolver>[0];
|
|
321
324
|
_step(): void;
|
|
@@ -385,6 +388,7 @@ declare class NetLabelPlacementSolver extends BaseSolver {
|
|
|
385
388
|
});
|
|
386
389
|
computeOverlappingSameNetTraceGroups(): Array<OverlappingSameNetTraceGroup>;
|
|
387
390
|
private getNetLabelWidthForGroup;
|
|
391
|
+
private getNetLabelHeightForGroup;
|
|
388
392
|
_step(): void;
|
|
389
393
|
visualize(): GraphicsObject;
|
|
390
394
|
}
|
|
@@ -700,6 +704,7 @@ declare class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
700
704
|
private findValidLateralShiftedCandidate;
|
|
701
705
|
private findValidCandidateInShiftColumn;
|
|
702
706
|
private evaluateCandidate;
|
|
707
|
+
private getCandidateConnectorTrace;
|
|
703
708
|
private getSearchStartAnchor;
|
|
704
709
|
private getWickOffsetAnchor;
|
|
705
710
|
private getSideOffsetAnchor;
|
|
@@ -707,6 +712,7 @@ declare class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
707
712
|
private getLateralColumnMaxDistance;
|
|
708
713
|
private createCandidate;
|
|
709
714
|
private getNetLabelWidth;
|
|
715
|
+
private getNetLabelHeight;
|
|
710
716
|
private getCandidateStatus;
|
|
711
717
|
private getBoundsStatus;
|
|
712
718
|
private intersectsAnyOtherNetLabel;
|
|
@@ -911,6 +917,7 @@ declare class NetLabelNetLabelCollisionSolver extends BaseSolver {
|
|
|
911
917
|
private collisionKey;
|
|
912
918
|
private findNextCollidingPair;
|
|
913
919
|
private netLabelWidthOf;
|
|
920
|
+
private netLabelHeightOf;
|
|
914
921
|
private buildCandidatesForLabel;
|
|
915
922
|
private checkCandidate;
|
|
916
923
|
private beginSearchForLabel;
|
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() {
|
|
@@ -5609,6 +5636,14 @@ var tracePathCrossesAnyBounds = (tracePath, bounds) => {
|
|
|
5609
5636
|
}
|
|
5610
5637
|
return false;
|
|
5611
5638
|
};
|
|
5639
|
+
var tracePathIntersectsBounds = (tracePath, bounds) => {
|
|
5640
|
+
for (let i = 0; i < tracePath.length - 1; i++) {
|
|
5641
|
+
if (segmentIntersectsRect2(tracePath[i], tracePath[i + 1], bounds)) {
|
|
5642
|
+
return true;
|
|
5643
|
+
}
|
|
5644
|
+
}
|
|
5645
|
+
return false;
|
|
5646
|
+
};
|
|
5612
5647
|
var tracePathCrossesAnyTrace = (tracePath, traceMap) => {
|
|
5613
5648
|
for (const trace of Object.values(traceMap)) {
|
|
5614
5649
|
const points = trace.tracePath;
|
|
@@ -5873,28 +5908,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
5873
5908
|
this.addConnectorTrace(label, candidate, labelIndex);
|
|
5874
5909
|
}
|
|
5875
5910
|
addConnectorTrace(label, candidate, labelIndex) {
|
|
5876
|
-
|
|
5877
|
-
if (candidate.phase === "lateral-shift") {
|
|
5878
|
-
const orientDir = dir(candidate.orientation);
|
|
5879
|
-
const kickedSource = {
|
|
5880
|
-
x: label.anchorPoint.x - orientDir.x * LABEL_SEARCH_STEP,
|
|
5881
|
-
y: label.anchorPoint.y - orientDir.y * LABEL_SEARCH_STEP
|
|
5882
|
-
};
|
|
5883
|
-
tracePath = simplifyOrthogonalPath([
|
|
5884
|
-
label.anchorPoint,
|
|
5885
|
-
...getConnectorTracePath(
|
|
5886
|
-
kickedSource,
|
|
5887
|
-
candidate.anchorPoint,
|
|
5888
|
-
candidate.orientation
|
|
5889
|
-
)
|
|
5890
|
-
]);
|
|
5891
|
-
} else {
|
|
5892
|
-
tracePath = getConnectorTracePath(
|
|
5893
|
-
label.anchorPoint,
|
|
5894
|
-
candidate.anchorPoint,
|
|
5895
|
-
candidate.orientation
|
|
5896
|
-
);
|
|
5897
|
-
}
|
|
5911
|
+
const tracePath = this.getCandidateConnectorTrace(label, candidate);
|
|
5898
5912
|
if (tracePath.length < 2) return;
|
|
5899
5913
|
const mspPairId = `available-net-orientation-${labelIndex}-${label.netId ?? label.globalConnNetId}`;
|
|
5900
5914
|
const connectorTrace = {
|
|
@@ -6077,14 +6091,42 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6077
6091
|
distance: distance3,
|
|
6078
6092
|
outwardDistance,
|
|
6079
6093
|
selected: false,
|
|
6080
|
-
status: this.getCandidateStatus(
|
|
6094
|
+
status: this.getCandidateStatus({
|
|
6095
|
+
candidate,
|
|
6096
|
+
label,
|
|
6097
|
+
labelIndex,
|
|
6098
|
+
phase
|
|
6099
|
+
})
|
|
6081
6100
|
};
|
|
6082
6101
|
}
|
|
6102
|
+
getCandidateConnectorTrace(label, candidate) {
|
|
6103
|
+
if (candidate.phase === "lateral-shift") {
|
|
6104
|
+
const orientDir = dir(candidate.orientation);
|
|
6105
|
+
const kickedSource = {
|
|
6106
|
+
x: label.anchorPoint.x - orientDir.x * LABEL_SEARCH_STEP,
|
|
6107
|
+
y: label.anchorPoint.y - orientDir.y * LABEL_SEARCH_STEP
|
|
6108
|
+
};
|
|
6109
|
+
return simplifyOrthogonalPath([
|
|
6110
|
+
label.anchorPoint,
|
|
6111
|
+
...getConnectorTracePath(
|
|
6112
|
+
kickedSource,
|
|
6113
|
+
candidate.anchorPoint,
|
|
6114
|
+
candidate.orientation
|
|
6115
|
+
)
|
|
6116
|
+
]);
|
|
6117
|
+
}
|
|
6118
|
+
return getConnectorTracePath(
|
|
6119
|
+
label.anchorPoint,
|
|
6120
|
+
candidate.anchorPoint,
|
|
6121
|
+
candidate.orientation
|
|
6122
|
+
);
|
|
6123
|
+
}
|
|
6083
6124
|
getSearchStartAnchor(label, orientation) {
|
|
6084
6125
|
const anchorPoint = this.getWickOffsetAnchor(label.anchorPoint, orientation);
|
|
6085
6126
|
const { width, height } = getDimsForOrientation({
|
|
6086
6127
|
orientation,
|
|
6087
|
-
netLabelWidth: this.getNetLabelWidth(label)
|
|
6128
|
+
netLabelWidth: this.getNetLabelWidth(label),
|
|
6129
|
+
netLabelHeight: this.getNetLabelHeight(label)
|
|
6088
6130
|
});
|
|
6089
6131
|
return this.getSideOffsetAnchor({
|
|
6090
6132
|
anchorPoint,
|
|
@@ -6133,7 +6175,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6133
6175
|
getSearchDistanceLimit(label, orientation) {
|
|
6134
6176
|
const { width, height } = getDimsForOrientation({
|
|
6135
6177
|
orientation,
|
|
6136
|
-
netLabelWidth: this.getNetLabelWidth(label)
|
|
6178
|
+
netLabelWidth: this.getNetLabelWidth(label),
|
|
6179
|
+
netLabelHeight: this.getNetLabelHeight(label)
|
|
6137
6180
|
});
|
|
6138
6181
|
const labelLength = orientation === "y+" || orientation === "y-" ? height : width;
|
|
6139
6182
|
return Math.min(this.maxSearchDistance, labelLength * 2);
|
|
@@ -6156,7 +6199,8 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6156
6199
|
createCandidate(label, anchorPoint, orientation) {
|
|
6157
6200
|
const { width, height } = getDimsForOrientation({
|
|
6158
6201
|
orientation,
|
|
6159
|
-
netLabelWidth: this.getNetLabelWidth(label)
|
|
6202
|
+
netLabelWidth: this.getNetLabelWidth(label),
|
|
6203
|
+
netLabelHeight: this.getNetLabelHeight(label)
|
|
6160
6204
|
});
|
|
6161
6205
|
return {
|
|
6162
6206
|
orientation,
|
|
@@ -6185,17 +6229,29 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6185
6229
|
(nc) => nc.pinIds.some((pid) => label.pinIds.includes(pid))
|
|
6186
6230
|
)?.netLabelWidth;
|
|
6187
6231
|
}
|
|
6188
|
-
|
|
6232
|
+
getNetLabelHeight(label) {
|
|
6233
|
+
if (label.netId) {
|
|
6234
|
+
const ncHeight = this.inputProblem.netConnections.find(
|
|
6235
|
+
(connection) => connection.netId === label.netId
|
|
6236
|
+
)?.netLabelHeight;
|
|
6237
|
+
if (ncHeight !== void 0) return ncHeight;
|
|
6238
|
+
}
|
|
6239
|
+
return this.inputProblem.netConnections.find(
|
|
6240
|
+
(nc) => nc.pinIds.some((pid) => label.pinIds.includes(pid))
|
|
6241
|
+
)?.netLabelHeight;
|
|
6242
|
+
}
|
|
6243
|
+
getCandidateStatus(params) {
|
|
6244
|
+
const { candidate, label, labelIndex, phase } = params;
|
|
6189
6245
|
const boundsStatus = this.getBoundsStatus(
|
|
6190
6246
|
getRectBounds(candidate.center, candidate.width, candidate.height),
|
|
6191
6247
|
labelIndex
|
|
6192
6248
|
);
|
|
6193
6249
|
if (boundsStatus !== "valid") return boundsStatus;
|
|
6194
|
-
const connectorTrace =
|
|
6195
|
-
|
|
6196
|
-
candidate.
|
|
6197
|
-
|
|
6198
|
-
);
|
|
6250
|
+
const connectorTrace = this.getCandidateConnectorTrace(label, {
|
|
6251
|
+
anchorPoint: candidate.anchorPoint,
|
|
6252
|
+
orientation: candidate.orientation,
|
|
6253
|
+
phase
|
|
6254
|
+
});
|
|
6199
6255
|
if (tracePathCrossesAnyTrace(connectorTrace, this.traceMap)) {
|
|
6200
6256
|
return "trace-collision";
|
|
6201
6257
|
}
|
|
@@ -6207,7 +6263,7 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6207
6263
|
for (let i = 0; i < this.outputNetLabelPlacements.length; i++) {
|
|
6208
6264
|
if (i === labelIndex) continue;
|
|
6209
6265
|
const otherLabel = this.outputNetLabelPlacements[i];
|
|
6210
|
-
if (
|
|
6266
|
+
if (tracePathIntersectsBounds(
|
|
6211
6267
|
connectorTrace,
|
|
6212
6268
|
getRectBounds(otherLabel.center, otherLabel.width, otherLabel.height)
|
|
6213
6269
|
)) {
|
|
@@ -6798,6 +6854,7 @@ var generateCandidatesAlongTrace = (params) => {
|
|
|
6798
6854
|
getTraceVertexDistances(traceLocation.trace)
|
|
6799
6855
|
);
|
|
6800
6856
|
const netLabelWidth = getNetLabelWidth(inputProblem, label);
|
|
6857
|
+
const netLabelHeight = getNetLabelHeight(inputProblem, label);
|
|
6801
6858
|
const candidates = [];
|
|
6802
6859
|
const seenCandidateKeys = /* @__PURE__ */ new Set();
|
|
6803
6860
|
for (const pathDistance of candidateDistances) {
|
|
@@ -6820,6 +6877,7 @@ var generateCandidatesAlongTrace = (params) => {
|
|
|
6820
6877
|
point,
|
|
6821
6878
|
orientation,
|
|
6822
6879
|
netLabelWidth,
|
|
6880
|
+
netLabelHeight,
|
|
6823
6881
|
traceLocation,
|
|
6824
6882
|
pathDistance,
|
|
6825
6883
|
label
|
|
@@ -6857,13 +6915,15 @@ var createCandidate = (params) => {
|
|
|
6857
6915
|
point,
|
|
6858
6916
|
orientation,
|
|
6859
6917
|
netLabelWidth,
|
|
6918
|
+
netLabelHeight,
|
|
6860
6919
|
traceLocation,
|
|
6861
6920
|
pathDistance,
|
|
6862
6921
|
label
|
|
6863
6922
|
} = params;
|
|
6864
6923
|
const { width, height } = getDimsForOrientation({
|
|
6865
6924
|
orientation,
|
|
6866
|
-
netLabelWidth
|
|
6925
|
+
netLabelWidth,
|
|
6926
|
+
netLabelHeight
|
|
6867
6927
|
});
|
|
6868
6928
|
return {
|
|
6869
6929
|
anchorPoint: point,
|
|
@@ -7026,6 +7086,15 @@ var getNetLabelWidth = (inputProblem, label) => {
|
|
|
7026
7086
|
}
|
|
7027
7087
|
return label.width;
|
|
7028
7088
|
};
|
|
7089
|
+
var getNetLabelHeight = (inputProblem, label) => {
|
|
7090
|
+
const ncHeightByNetId = inputProblem.netConnections.find(
|
|
7091
|
+
(connection) => connection.netId === label.netId
|
|
7092
|
+
)?.netLabelHeight;
|
|
7093
|
+
if (ncHeightByNetId !== void 0) return ncHeightByNetId;
|
|
7094
|
+
return inputProblem.netConnections.find(
|
|
7095
|
+
(nc) => nc.pinIds.some((pid) => label.pinIds.includes(pid))
|
|
7096
|
+
)?.netLabelHeight;
|
|
7097
|
+
};
|
|
7029
7098
|
var roundDistance = (distance3) => Number(distance3.toFixed(6));
|
|
7030
7099
|
var dedupeOrientations = (orientations) => [
|
|
7031
7100
|
...new Set(orientations)
|
|
@@ -7437,16 +7506,14 @@ function buildMergedObstacleLabel(seedLabel, allLabels) {
|
|
|
7437
7506
|
height: h
|
|
7438
7507
|
};
|
|
7439
7508
|
}
|
|
7440
|
-
function
|
|
7509
|
+
function detectTraceLabelOverlaps(traces, labels) {
|
|
7441
7510
|
const overlaps = [];
|
|
7442
7511
|
for (const trace of traces) {
|
|
7443
7512
|
for (const label of labels) {
|
|
7444
7513
|
if (trace.globalConnNetId === label.globalConnNetId) continue;
|
|
7445
7514
|
const bounds = getRectBounds(label.center, label.width, label.height);
|
|
7446
7515
|
const path = trace.tracePath;
|
|
7447
|
-
|
|
7448
|
-
const innerEnd = path.length - 2;
|
|
7449
|
-
for (let i = innerStart; i < innerEnd; i++) {
|
|
7516
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
7450
7517
|
if (segmentIntersectsRect2(path[i], path[i + 1], bounds)) {
|
|
7451
7518
|
overlaps.push({ trace, label });
|
|
7452
7519
|
break;
|
|
@@ -7512,7 +7579,7 @@ var NetLabelTraceCollisionSolver = class extends BaseSolver {
|
|
|
7512
7579
|
}
|
|
7513
7580
|
return;
|
|
7514
7581
|
}
|
|
7515
|
-
const overlaps =
|
|
7582
|
+
const overlaps = detectTraceLabelOverlaps(
|
|
7516
7583
|
this.outputTraces,
|
|
7517
7584
|
this.outputNetLabelPlacements
|
|
7518
7585
|
);
|
|
@@ -7702,13 +7769,20 @@ var NetLabelNetLabelCollisionSolver = class extends BaseSolver {
|
|
|
7702
7769
|
return label.width;
|
|
7703
7770
|
return label.height;
|
|
7704
7771
|
}
|
|
7772
|
+
netLabelHeightOf(label) {
|
|
7773
|
+
if (label.orientation === "x+" || label.orientation === "x-")
|
|
7774
|
+
return label.height;
|
|
7775
|
+
return label.width;
|
|
7776
|
+
}
|
|
7705
7777
|
buildCandidatesForLabel(label) {
|
|
7706
7778
|
const netLabelWidth = this.netLabelWidthOf(label);
|
|
7779
|
+
const netLabelHeight = this.netLabelHeightOf(label);
|
|
7707
7780
|
const candidates = [];
|
|
7708
7781
|
const buildCandidate = (orientation, anchor, hostPairId, hostSegIndex) => {
|
|
7709
7782
|
const { width, height } = getDimsForOrientation({
|
|
7710
7783
|
orientation,
|
|
7711
|
-
netLabelWidth
|
|
7784
|
+
netLabelWidth,
|
|
7785
|
+
netLabelHeight
|
|
7712
7786
|
});
|
|
7713
7787
|
const baseCenter = getCenterFromAnchor(anchor, orientation, width, height);
|
|
7714
7788
|
const outwardDir = OUTWARD_DIR[orientation];
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
rectsOverlap,
|
|
23
23
|
simplifyOrthogonalPath,
|
|
24
24
|
traceCrossesBoundsInterior,
|
|
25
|
+
tracePathIntersectsBounds,
|
|
25
26
|
tracePathCrossesAnyBounds,
|
|
26
27
|
tracePathCrossesAnyTrace,
|
|
27
28
|
} from "./geometry"
|
|
@@ -143,30 +144,7 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
143
144
|
candidate: EvaluatedCandidate,
|
|
144
145
|
labelIndex: number,
|
|
145
146
|
) {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
if (candidate.phase === "lateral-shift") {
|
|
149
|
-
const orientDir = dir(candidate.orientation)
|
|
150
|
-
const kickedSource = {
|
|
151
|
-
x: label.anchorPoint.x - orientDir.x * LABEL_SEARCH_STEP,
|
|
152
|
-
y: label.anchorPoint.y - orientDir.y * LABEL_SEARCH_STEP,
|
|
153
|
-
}
|
|
154
|
-
tracePath = simplifyOrthogonalPath([
|
|
155
|
-
label.anchorPoint,
|
|
156
|
-
...getConnectorTracePath(
|
|
157
|
-
kickedSource,
|
|
158
|
-
candidate.anchorPoint,
|
|
159
|
-
candidate.orientation,
|
|
160
|
-
),
|
|
161
|
-
])
|
|
162
|
-
} else {
|
|
163
|
-
tracePath = getConnectorTracePath(
|
|
164
|
-
label.anchorPoint,
|
|
165
|
-
candidate.anchorPoint,
|
|
166
|
-
candidate.orientation,
|
|
167
|
-
)
|
|
168
|
-
}
|
|
169
|
-
|
|
147
|
+
const tracePath = this.getCandidateConnectorTrace(label, candidate)
|
|
170
148
|
if (tracePath.length < 2) return
|
|
171
149
|
|
|
172
150
|
const mspPairId = `available-net-orientation-${labelIndex}-${label.netId ?? label.globalConnNetId}`
|
|
@@ -417,8 +395,43 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
417
395
|
distance,
|
|
418
396
|
outwardDistance,
|
|
419
397
|
selected: false,
|
|
420
|
-
status: this.getCandidateStatus(
|
|
398
|
+
status: this.getCandidateStatus({
|
|
399
|
+
candidate,
|
|
400
|
+
label,
|
|
401
|
+
labelIndex,
|
|
402
|
+
phase,
|
|
403
|
+
}),
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
private getCandidateConnectorTrace(
|
|
408
|
+
label: NetLabelPlacement,
|
|
409
|
+
candidate: Pick<
|
|
410
|
+
EvaluatedCandidate,
|
|
411
|
+
"anchorPoint" | "orientation" | "phase"
|
|
412
|
+
>,
|
|
413
|
+
) {
|
|
414
|
+
if (candidate.phase === "lateral-shift") {
|
|
415
|
+
const orientDir = dir(candidate.orientation)
|
|
416
|
+
const kickedSource = {
|
|
417
|
+
x: label.anchorPoint.x - orientDir.x * LABEL_SEARCH_STEP,
|
|
418
|
+
y: label.anchorPoint.y - orientDir.y * LABEL_SEARCH_STEP,
|
|
419
|
+
}
|
|
420
|
+
return simplifyOrthogonalPath([
|
|
421
|
+
label.anchorPoint,
|
|
422
|
+
...getConnectorTracePath(
|
|
423
|
+
kickedSource,
|
|
424
|
+
candidate.anchorPoint,
|
|
425
|
+
candidate.orientation,
|
|
426
|
+
),
|
|
427
|
+
])
|
|
421
428
|
}
|
|
429
|
+
|
|
430
|
+
return getConnectorTracePath(
|
|
431
|
+
label.anchorPoint,
|
|
432
|
+
candidate.anchorPoint,
|
|
433
|
+
candidate.orientation,
|
|
434
|
+
)
|
|
422
435
|
}
|
|
423
436
|
|
|
424
437
|
private getSearchStartAnchor(
|
|
@@ -429,6 +442,7 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
429
442
|
const { width, height } = getDimsForOrientation({
|
|
430
443
|
orientation,
|
|
431
444
|
netLabelWidth: this.getNetLabelWidth(label),
|
|
445
|
+
netLabelHeight: this.getNetLabelHeight(label),
|
|
432
446
|
})
|
|
433
447
|
|
|
434
448
|
return this.getSideOffsetAnchor({
|
|
@@ -494,6 +508,7 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
494
508
|
const { width, height } = getDimsForOrientation({
|
|
495
509
|
orientation,
|
|
496
510
|
netLabelWidth: this.getNetLabelWidth(label),
|
|
511
|
+
netLabelHeight: this.getNetLabelHeight(label),
|
|
497
512
|
})
|
|
498
513
|
const labelLength =
|
|
499
514
|
orientation === "y+" || orientation === "y-" ? height : width
|
|
@@ -534,6 +549,7 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
534
549
|
const { width, height } = getDimsForOrientation({
|
|
535
550
|
orientation,
|
|
536
551
|
netLabelWidth: this.getNetLabelWidth(label),
|
|
552
|
+
netLabelHeight: this.getNetLabelHeight(label),
|
|
537
553
|
})
|
|
538
554
|
return {
|
|
539
555
|
orientation,
|
|
@@ -567,22 +583,37 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
567
583
|
)?.netLabelWidth
|
|
568
584
|
}
|
|
569
585
|
|
|
570
|
-
private
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
586
|
+
private getNetLabelHeight(label: NetLabelPlacement) {
|
|
587
|
+
if (label.netId) {
|
|
588
|
+
const ncHeight = this.inputProblem.netConnections.find(
|
|
589
|
+
(connection) => connection.netId === label.netId,
|
|
590
|
+
)?.netLabelHeight
|
|
591
|
+
if (ncHeight !== undefined) return ncHeight
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
return this.inputProblem.netConnections.find((nc) =>
|
|
595
|
+
nc.pinIds.some((pid) => label.pinIds.includes(pid)),
|
|
596
|
+
)?.netLabelHeight
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
private getCandidateStatus(params: {
|
|
600
|
+
candidate: CandidateLabel
|
|
601
|
+
label: NetLabelPlacement
|
|
602
|
+
labelIndex: number
|
|
603
|
+
phase: CandidatePhase
|
|
604
|
+
}) {
|
|
605
|
+
const { candidate, label, labelIndex, phase } = params
|
|
575
606
|
const boundsStatus = this.getBoundsStatus(
|
|
576
607
|
getRectBounds(candidate.center, candidate.width, candidate.height),
|
|
577
608
|
labelIndex,
|
|
578
609
|
)
|
|
579
610
|
if (boundsStatus !== "valid") return boundsStatus
|
|
580
611
|
|
|
581
|
-
const connectorTrace =
|
|
582
|
-
|
|
583
|
-
candidate.
|
|
584
|
-
|
|
585
|
-
)
|
|
612
|
+
const connectorTrace = this.getCandidateConnectorTrace(label, {
|
|
613
|
+
anchorPoint: candidate.anchorPoint,
|
|
614
|
+
orientation: candidate.orientation,
|
|
615
|
+
phase,
|
|
616
|
+
})
|
|
586
617
|
|
|
587
618
|
if (tracePathCrossesAnyTrace(connectorTrace, this.traceMap)) {
|
|
588
619
|
return "trace-collision"
|
|
@@ -598,7 +629,7 @@ export class AvailableNetOrientationSolver extends BaseSolver {
|
|
|
598
629
|
if (i === labelIndex) continue
|
|
599
630
|
const otherLabel = this.outputNetLabelPlacements[i]!
|
|
600
631
|
if (
|
|
601
|
-
|
|
632
|
+
tracePathIntersectsBounds(
|
|
602
633
|
connectorTrace,
|
|
603
634
|
getRectBounds(otherLabel.center, otherLabel.width, otherLabel.height),
|
|
604
635
|
)
|
|
@@ -2,6 +2,7 @@ import type { Point } from "@tscircuit/math-utils"
|
|
|
2
2
|
import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
3
3
|
import type { InputProblem } from "lib/types/InputProblem"
|
|
4
4
|
import type { FacingDirection } from "lib/utils/dir"
|
|
5
|
+
import { segmentIntersectsRect } from "lib/solvers/NetLabelPlacementSolver/SingleNetLabelPlacementSolver/collisions"
|
|
5
6
|
import { EPS, TRACE_BOUNDARY_TOLERANCE } from "./constants"
|
|
6
7
|
import type { Bounds, ChipSide } from "./types"
|
|
7
8
|
|
|
@@ -102,6 +103,18 @@ export const tracePathCrossesAnyBounds = (
|
|
|
102
103
|
return false
|
|
103
104
|
}
|
|
104
105
|
|
|
106
|
+
export const tracePathIntersectsBounds = (
|
|
107
|
+
tracePath: Point[],
|
|
108
|
+
bounds: Bounds,
|
|
109
|
+
) => {
|
|
110
|
+
for (let i = 0; i < tracePath.length - 1; i++) {
|
|
111
|
+
if (segmentIntersectsRect(tracePath[i]!, tracePath[i + 1]!, bounds)) {
|
|
112
|
+
return true
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return false
|
|
116
|
+
}
|
|
117
|
+
|
|
105
118
|
export const tracePathCrossesAnyTrace = (
|
|
106
119
|
tracePath: Point[],
|
|
107
120
|
traceMap: Record<string, SolvedTracePath>,
|
|
@@ -170,8 +170,15 @@ export class NetLabelNetLabelCollisionSolver extends BaseSolver {
|
|
|
170
170
|
return label.height
|
|
171
171
|
}
|
|
172
172
|
|
|
173
|
+
private netLabelHeightOf(label: NetLabelPlacement): number | undefined {
|
|
174
|
+
if (label.orientation === "x+" || label.orientation === "x-")
|
|
175
|
+
return label.height
|
|
176
|
+
return label.width
|
|
177
|
+
}
|
|
178
|
+
|
|
173
179
|
private buildCandidatesForLabel(label: NetLabelPlacement): Candidate[] {
|
|
174
180
|
const netLabelWidth = this.netLabelWidthOf(label)
|
|
181
|
+
const netLabelHeight = this.netLabelHeightOf(label)
|
|
175
182
|
const candidates: Candidate[] = []
|
|
176
183
|
|
|
177
184
|
const buildCandidate = (
|
|
@@ -183,6 +190,7 @@ export class NetLabelNetLabelCollisionSolver extends BaseSolver {
|
|
|
183
190
|
const { width, height } = getDimsForOrientation({
|
|
184
191
|
orientation,
|
|
185
192
|
netLabelWidth,
|
|
193
|
+
netLabelHeight,
|
|
186
194
|
})
|
|
187
195
|
const baseCenter = getCenterFromAnchor(anchor, orientation, width, height)
|
|
188
196
|
const outwardDir = OUTWARD_DIR[orientation]
|