@tscircuit/schematic-trace-solver 0.0.164 → 0.0.166
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 +5 -1
- package/dist/index.js +370 -24
- package/lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts +225 -24
- package/lib/solvers/SameNetJunctionAlignmentSolver/SameNetJunctionAlignmentSolver.ts +11 -5
- package/lib/solvers/SameNetJunctionAlignmentSolver/alignSameNetJunctions.ts +1 -1
- package/lib/solvers/SameNetJunctionAlignmentSolver/collapseSameNetCycles.ts +310 -0
- package/package.json +1 -1
- package/tests/assets/example51.json +6 -0
- package/tests/bug-reports/bug-report-20260721T221026Z/__snapshots__/bug-report-20260721T221026Z.snap.svg +2 -2
- package/tests/examples/__snapshots__/example51.snap.svg +42 -78
- package/tests/examples/example51.test.ts +24 -0
- package/tests/fixtures/convertSolverOutputToCircuitJson.ts +22 -3
- package/tests/repros/__snapshots__/board-1273-trace-overlap-cycle.snap.svg +2 -2
- package/tests/repros/__snapshots__/repro-bluetooth-controller-ground-decoupling-groups.snap.svg +1 -15
- package/tests/repros/__snapshots__/repro-core-ground-inline-label-fallback.snap.svg +2 -16
- package/tests/repros/__snapshots__/repro-isolated-rs485-isow7841.snap.svg +10 -10
- package/tests/repros/__snapshots__/repro-nrf52810-clock-routing.snap.svg +18 -18
- package/tests/repros/__snapshots__/repro-pga300-redundant-ground-traces.snap.svg +1 -15
- package/tests/repros/__snapshots__/repro-pmp11282-isolated-dcdc.snap.svg +33 -47
- package/tests/repros/repro-board-648-esp12f-section.test.ts +3 -0
- package/tests/repros/repro-isolated-rs485-isow7841.test.ts +33 -1
- package/tests/repros/repro-nrf52810-clock-routing.test.ts +26 -1
- package/tests/solvers/SameNetJunctionAlignmentSolver/collapse-same-net-cycles.test.ts +154 -0
package/dist/index.d.ts
CHANGED
|
@@ -1394,11 +1394,15 @@ declare class NetLabelToTraceSolver extends BaseSolver {
|
|
|
1394
1394
|
activeSubSolver: SchematicTraceSingleLineSolver2 | null;
|
|
1395
1395
|
constructor(input: InlineNetLabelOutput);
|
|
1396
1396
|
getConstructorParams(): [InlineNetLabelOutput];
|
|
1397
|
-
private
|
|
1397
|
+
private isPortOnlyFallbackLabel;
|
|
1398
|
+
private isDirectConnectionLabel;
|
|
1399
|
+
private getMultiPinNetConnection;
|
|
1398
1400
|
private buildCandidatePairs;
|
|
1401
|
+
private buildRoutedComponentCandidates;
|
|
1399
1402
|
private isSupersededConnectorTrace;
|
|
1400
1403
|
private routeIntersectsRemainingLabels;
|
|
1401
1404
|
private tryAcceptCurrentRoute;
|
|
1405
|
+
private areCandidatePinsAlreadyConnected;
|
|
1402
1406
|
_step(): void;
|
|
1403
1407
|
getOutput(): {
|
|
1404
1408
|
traces: SolvedTracePath[];
|
package/dist/index.js
CHANGED
|
@@ -13009,6 +13009,214 @@ var alignSameNetJunctions = ({
|
|
|
13009
13009
|
};
|
|
13010
13010
|
};
|
|
13011
13011
|
|
|
13012
|
+
// lib/solvers/SameNetJunctionAlignmentSolver/collapseSameNetCycles.ts
|
|
13013
|
+
import { getSegmentIntersection as getSegmentIntersection4 } from "@tscircuit/math-utils/line-intersections";
|
|
13014
|
+
var TRACE_LENGTH_EPSILON = 1e-6;
|
|
13015
|
+
var getTracePathStartingAtPin = (trace, pin) => {
|
|
13016
|
+
const pathStart = trace.tracePath[0];
|
|
13017
|
+
const pathEnd = trace.tracePath.at(-1);
|
|
13018
|
+
if (!pathStart || !pathEnd) return null;
|
|
13019
|
+
if (pointsEqual(pathStart, pin)) return trace.tracePath;
|
|
13020
|
+
if (pointsEqual(pathEnd, pin)) return [...trace.tracePath].reverse();
|
|
13021
|
+
return null;
|
|
13022
|
+
};
|
|
13023
|
+
var getPerpendicularPathCrossings = (targetPath, donorPath) => {
|
|
13024
|
+
const crossings = [];
|
|
13025
|
+
const sharedEndpoint = targetPath[0];
|
|
13026
|
+
for (let targetSegmentIndex = 0; targetSegmentIndex < targetPath.length - 1; targetSegmentIndex++) {
|
|
13027
|
+
const targetStart = targetPath[targetSegmentIndex];
|
|
13028
|
+
const targetEnd = targetPath[targetSegmentIndex + 1];
|
|
13029
|
+
const targetOrientation = getRailOrientation(targetStart, targetEnd);
|
|
13030
|
+
if (!targetOrientation) continue;
|
|
13031
|
+
for (let donorSegmentIndex = 0; donorSegmentIndex < donorPath.length - 1; donorSegmentIndex++) {
|
|
13032
|
+
const donorStart = donorPath[donorSegmentIndex];
|
|
13033
|
+
const donorEnd = donorPath[donorSegmentIndex + 1];
|
|
13034
|
+
const donorOrientation = getRailOrientation(donorStart, donorEnd);
|
|
13035
|
+
if (!donorOrientation || donorOrientation === targetOrientation) continue;
|
|
13036
|
+
const intersectionPoint = getSegmentIntersection4(
|
|
13037
|
+
targetStart,
|
|
13038
|
+
targetEnd,
|
|
13039
|
+
donorStart,
|
|
13040
|
+
donorEnd
|
|
13041
|
+
);
|
|
13042
|
+
if (!intersectionPoint || pointsEqual(intersectionPoint, sharedEndpoint)) {
|
|
13043
|
+
continue;
|
|
13044
|
+
}
|
|
13045
|
+
crossings.push({
|
|
13046
|
+
intersectionPoint,
|
|
13047
|
+
targetSegmentIndex,
|
|
13048
|
+
donorSegmentIndex
|
|
13049
|
+
});
|
|
13050
|
+
}
|
|
13051
|
+
}
|
|
13052
|
+
return crossings;
|
|
13053
|
+
};
|
|
13054
|
+
var buildCollapsedCyclePath = ({
|
|
13055
|
+
targetTrace,
|
|
13056
|
+
targetPath,
|
|
13057
|
+
donorPath,
|
|
13058
|
+
crossing
|
|
13059
|
+
}) => {
|
|
13060
|
+
const pathFromSharedPin = simplifyPath([
|
|
13061
|
+
...donorPath.slice(0, crossing.donorSegmentIndex + 1),
|
|
13062
|
+
crossing.intersectionPoint,
|
|
13063
|
+
...targetPath.slice(crossing.targetSegmentIndex + 1)
|
|
13064
|
+
]);
|
|
13065
|
+
if (pointsEqual(targetTrace.tracePath[0], targetPath[0])) {
|
|
13066
|
+
return pathFromSharedPin;
|
|
13067
|
+
}
|
|
13068
|
+
return pathFromSharedPin.reverse();
|
|
13069
|
+
};
|
|
13070
|
+
var getNetLabelPlacementsForCycleCollapse = ({
|
|
13071
|
+
targetTrace,
|
|
13072
|
+
tracePath,
|
|
13073
|
+
netLabelPlacements
|
|
13074
|
+
}) => {
|
|
13075
|
+
const candidateNetLabelPlacements = moveAttachedLabelsToReroutedTrace({
|
|
13076
|
+
trace: targetTrace,
|
|
13077
|
+
originalTracePath: targetTrace.tracePath,
|
|
13078
|
+
reroutedTracePath: tracePath,
|
|
13079
|
+
netLabelPlacements
|
|
13080
|
+
});
|
|
13081
|
+
for (let labelIndex = 0; labelIndex < netLabelPlacements.length; labelIndex++) {
|
|
13082
|
+
const label = netLabelPlacements[labelIndex];
|
|
13083
|
+
if (label.globalConnNetId !== targetTrace.globalConnNetId) continue;
|
|
13084
|
+
if (!tracePathContainsPoint(targetTrace.tracePath, label.anchorPoint)) {
|
|
13085
|
+
continue;
|
|
13086
|
+
}
|
|
13087
|
+
const candidateLabel = candidateNetLabelPlacements[labelIndex];
|
|
13088
|
+
if (!tracePathContainsPoint(tracePath, candidateLabel.anchorPoint)) {
|
|
13089
|
+
return null;
|
|
13090
|
+
}
|
|
13091
|
+
}
|
|
13092
|
+
const otherNetLabelPlacements = candidateNetLabelPlacements.filter(
|
|
13093
|
+
(label) => label.globalConnNetId !== targetTrace.globalConnNetId
|
|
13094
|
+
);
|
|
13095
|
+
if (pathIntersectsAnyNetLabel({
|
|
13096
|
+
path: tracePath,
|
|
13097
|
+
netLabelPlacements: otherNetLabelPlacements
|
|
13098
|
+
})) {
|
|
13099
|
+
return null;
|
|
13100
|
+
}
|
|
13101
|
+
const sameNetLabelPlacements = candidateNetLabelPlacements.filter(
|
|
13102
|
+
(label) => label.globalConnNetId === targetTrace.globalConnNetId
|
|
13103
|
+
);
|
|
13104
|
+
if (pathEntersAnyNetLabel({
|
|
13105
|
+
path: tracePath,
|
|
13106
|
+
netLabelPlacements: sameNetLabelPlacements
|
|
13107
|
+
})) {
|
|
13108
|
+
return null;
|
|
13109
|
+
}
|
|
13110
|
+
return candidateNetLabelPlacements;
|
|
13111
|
+
};
|
|
13112
|
+
var candidateIsBetter = (candidate, bestCandidate) => {
|
|
13113
|
+
if (!bestCandidate) return true;
|
|
13114
|
+
const visibleLengthDelta = candidate.netVisibleLength - bestCandidate.netVisibleLength;
|
|
13115
|
+
if (Math.abs(visibleLengthDelta) > TRACE_LENGTH_EPSILON) {
|
|
13116
|
+
return visibleLengthDelta < 0;
|
|
13117
|
+
}
|
|
13118
|
+
return candidate.netVisibleSegmentCount < bestCandidate.netVisibleSegmentCount;
|
|
13119
|
+
};
|
|
13120
|
+
var getBestCycleCollapseCandidate = ({
|
|
13121
|
+
targetTrace,
|
|
13122
|
+
traces,
|
|
13123
|
+
netLabelPlacements
|
|
13124
|
+
}) => {
|
|
13125
|
+
const sameNetTraces = traces.filter(
|
|
13126
|
+
(trace) => trace.globalConnNetId === targetTrace.globalConnNetId
|
|
13127
|
+
);
|
|
13128
|
+
const baselineNetVisibleLength = getVisibleTraceLength(sameNetTraces);
|
|
13129
|
+
const baselineTargetVisibleLength = getVisibleTraceLength([targetTrace]);
|
|
13130
|
+
let bestCandidate = null;
|
|
13131
|
+
for (const donorTrace of sameNetTraces) {
|
|
13132
|
+
if (donorTrace.mspPairId === targetTrace.mspPairId) continue;
|
|
13133
|
+
const sharedPin = getSharedPin({
|
|
13134
|
+
donorTrace,
|
|
13135
|
+
branchTrace: targetTrace
|
|
13136
|
+
});
|
|
13137
|
+
if (!sharedPin) continue;
|
|
13138
|
+
const targetPath = getTracePathStartingAtPin(targetTrace, sharedPin);
|
|
13139
|
+
const donorPath = getTracePathStartingAtPin(donorTrace, sharedPin);
|
|
13140
|
+
if (!targetPath || !donorPath) continue;
|
|
13141
|
+
const crossings = getPerpendicularPathCrossings(targetPath, donorPath);
|
|
13142
|
+
for (const crossing of crossings) {
|
|
13143
|
+
const tracePath = buildCollapsedCyclePath({
|
|
13144
|
+
targetTrace,
|
|
13145
|
+
targetPath,
|
|
13146
|
+
donorPath,
|
|
13147
|
+
crossing
|
|
13148
|
+
});
|
|
13149
|
+
const candidateTrace = { ...targetTrace, tracePath };
|
|
13150
|
+
const candidateTargetVisibleLength = getVisibleTraceLength([
|
|
13151
|
+
candidateTrace
|
|
13152
|
+
]);
|
|
13153
|
+
if (candidateTargetVisibleLength > baselineTargetVisibleLength + TRACE_LENGTH_EPSILON) {
|
|
13154
|
+
continue;
|
|
13155
|
+
}
|
|
13156
|
+
const candidateNetLabelPlacements = getNetLabelPlacementsForCycleCollapse(
|
|
13157
|
+
{
|
|
13158
|
+
targetTrace,
|
|
13159
|
+
tracePath,
|
|
13160
|
+
netLabelPlacements
|
|
13161
|
+
}
|
|
13162
|
+
);
|
|
13163
|
+
if (!candidateNetLabelPlacements) continue;
|
|
13164
|
+
const candidateNetTraces = sameNetTraces.map((trace) => {
|
|
13165
|
+
if (trace.mspPairId === targetTrace.mspPairId) return candidateTrace;
|
|
13166
|
+
return trace;
|
|
13167
|
+
});
|
|
13168
|
+
const netVisibleLength = getVisibleTraceLength(candidateNetTraces);
|
|
13169
|
+
if (netVisibleLength >= baselineNetVisibleLength - TRACE_LENGTH_EPSILON) {
|
|
13170
|
+
continue;
|
|
13171
|
+
}
|
|
13172
|
+
const netVisibleSegmentCount = getVisibleTraceSegmentCount(candidateNetTraces);
|
|
13173
|
+
const candidate = {
|
|
13174
|
+
tracePath,
|
|
13175
|
+
netLabelPlacements: candidateNetLabelPlacements,
|
|
13176
|
+
netVisibleLength,
|
|
13177
|
+
netVisibleSegmentCount
|
|
13178
|
+
};
|
|
13179
|
+
if (candidateIsBetter(candidate, bestCandidate)) {
|
|
13180
|
+
bestCandidate = candidate;
|
|
13181
|
+
}
|
|
13182
|
+
}
|
|
13183
|
+
}
|
|
13184
|
+
return bestCandidate;
|
|
13185
|
+
};
|
|
13186
|
+
var collapseSameNetCycles = ({
|
|
13187
|
+
traces,
|
|
13188
|
+
netLabelPlacements
|
|
13189
|
+
}) => {
|
|
13190
|
+
const outputTraces = [...traces];
|
|
13191
|
+
let outputNetLabelPlacements = [...netLabelPlacements];
|
|
13192
|
+
let collapsedCycleCount = 0;
|
|
13193
|
+
let traceIndex = 0;
|
|
13194
|
+
while (traceIndex < outputTraces.length) {
|
|
13195
|
+
const targetTrace = outputTraces[traceIndex];
|
|
13196
|
+
const candidate = getBestCycleCollapseCandidate({
|
|
13197
|
+
targetTrace,
|
|
13198
|
+
traces: outputTraces,
|
|
13199
|
+
netLabelPlacements: outputNetLabelPlacements
|
|
13200
|
+
});
|
|
13201
|
+
if (!candidate) {
|
|
13202
|
+
traceIndex++;
|
|
13203
|
+
continue;
|
|
13204
|
+
}
|
|
13205
|
+
outputTraces[traceIndex] = {
|
|
13206
|
+
...targetTrace,
|
|
13207
|
+
tracePath: candidate.tracePath
|
|
13208
|
+
};
|
|
13209
|
+
outputNetLabelPlacements = candidate.netLabelPlacements;
|
|
13210
|
+
collapsedCycleCount++;
|
|
13211
|
+
traceIndex = 0;
|
|
13212
|
+
}
|
|
13213
|
+
return {
|
|
13214
|
+
traces: outputTraces,
|
|
13215
|
+
netLabelPlacements: outputNetLabelPlacements,
|
|
13216
|
+
collapsedCycleCount
|
|
13217
|
+
};
|
|
13218
|
+
};
|
|
13219
|
+
|
|
13012
13220
|
// lib/solvers/SameNetJunctionAlignmentSolver/placeGroundRailLabelsAtOuterEnd.ts
|
|
13013
13221
|
var placeGroundRailLabelsAtOuterEnd = ({
|
|
13014
13222
|
inputProblem,
|
|
@@ -13090,14 +13298,19 @@ var SameNetJunctionAlignmentSolver = class extends BaseSolver {
|
|
|
13090
13298
|
this.outputNetLabelPlacements = input.netLabelPlacements;
|
|
13091
13299
|
}
|
|
13092
13300
|
_step() {
|
|
13093
|
-
const
|
|
13094
|
-
|
|
13301
|
+
const alignment = alignSameNetJunctions(this.input);
|
|
13302
|
+
const cycleCollapse = collapseSameNetCycles({
|
|
13303
|
+
traces: alignment.traces,
|
|
13304
|
+
netLabelPlacements: alignment.netLabelPlacements
|
|
13305
|
+
});
|
|
13306
|
+
this.outputTraces = cycleCollapse.traces;
|
|
13095
13307
|
this.outputNetLabelPlacements = placeGroundRailLabelsAtOuterEnd({
|
|
13096
13308
|
inputProblem: this.input.inputProblem,
|
|
13097
|
-
traces:
|
|
13098
|
-
netLabelPlacements:
|
|
13309
|
+
traces: cycleCollapse.traces,
|
|
13310
|
+
netLabelPlacements: cycleCollapse.netLabelPlacements
|
|
13099
13311
|
});
|
|
13100
|
-
this.stats.alignedJunctionCount =
|
|
13312
|
+
this.stats.alignedJunctionCount = alignment.alignedJunctionCount;
|
|
13313
|
+
this.stats.collapsedCycleCount = cycleCollapse.collapsedCycleCount;
|
|
13101
13314
|
this.solved = true;
|
|
13102
13315
|
}
|
|
13103
13316
|
getOutput() {
|
|
@@ -15051,6 +15264,8 @@ var getTraceRecoveryConnectivityMaps = (inputProblem) => {
|
|
|
15051
15264
|
// lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts
|
|
15052
15265
|
var AVAILABLE_NET_ORIENTATION_PREFIX = "available-net-orientation-";
|
|
15053
15266
|
var RECOVERED_TRACE_PREFIX = "net-label-to-trace-";
|
|
15267
|
+
var MAX_NAMED_NET_RECOVERY_PERPENDICULAR_OFFSET = 0.05;
|
|
15268
|
+
var MAX_ROUTED_COMPONENT_RECOVERY_PERPENDICULAR_OFFSET = 0.25;
|
|
15054
15269
|
var getCanonicalPairKey = (firstPinId, secondPinId) => [firstPinId, secondPinId].sort().join("--");
|
|
15055
15270
|
var pathIntersectsRenderedLabel = (path, label) => {
|
|
15056
15271
|
let width = label.width;
|
|
@@ -15071,12 +15286,21 @@ var pathIntersectsRenderedLabel = (path, label) => {
|
|
|
15071
15286
|
}
|
|
15072
15287
|
return false;
|
|
15073
15288
|
};
|
|
15074
|
-
var getPerpendicularOffset = (
|
|
15075
|
-
const xDistance = Math.abs(
|
|
15076
|
-
const yDistance = Math.abs(
|
|
15289
|
+
var getPerpendicularOffset = (firstPoint, secondPoint) => {
|
|
15290
|
+
const xDistance = Math.abs(firstPoint.x - secondPoint.x);
|
|
15291
|
+
const yDistance = Math.abs(firstPoint.y - secondPoint.y);
|
|
15077
15292
|
if (xDistance >= yDistance) return yDistance;
|
|
15078
15293
|
return xDistance;
|
|
15079
15294
|
};
|
|
15295
|
+
var arePinsCoFacingAlongSeparationAxis = (firstPin, secondPin) => {
|
|
15296
|
+
if (firstPin._facingDirection !== secondPin._facingDirection) return false;
|
|
15297
|
+
const xDistance = Math.abs(firstPin.x - secondPin.x);
|
|
15298
|
+
const yDistance = Math.abs(firstPin.y - secondPin.y);
|
|
15299
|
+
if (xDistance >= yDistance) {
|
|
15300
|
+
return firstPin._facingDirection === "x+" || firstPin._facingDirection === "x-";
|
|
15301
|
+
}
|
|
15302
|
+
return firstPin._facingDirection === "y+" || firstPin._facingDirection === "y-";
|
|
15303
|
+
};
|
|
15080
15304
|
var NetLabelToTraceSolver = class extends BaseSolver {
|
|
15081
15305
|
constructor(input) {
|
|
15082
15306
|
super();
|
|
@@ -15104,26 +15328,36 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
15104
15328
|
getConstructorParams() {
|
|
15105
15329
|
return [this.input];
|
|
15106
15330
|
}
|
|
15107
|
-
|
|
15108
|
-
|
|
15109
|
-
|
|
15110
|
-
|
|
15331
|
+
isPortOnlyFallbackLabel(label, groundGlobalConnNetIds) {
|
|
15332
|
+
return !(label.pinIds.length !== 1 || label.mspConnectionPairIds.length !== 0 || !label.netId || groundGlobalConnNetIds.has(label.globalConnNetId));
|
|
15333
|
+
}
|
|
15334
|
+
isDirectConnectionLabel(label) {
|
|
15335
|
+
if (!label.netId || label.pinIds.length !== 1) return false;
|
|
15111
15336
|
const pinId = label.pinIds[0];
|
|
15112
15337
|
return this.inputProblem.directConnections.some(
|
|
15113
15338
|
(connection) => connection.netId === label.netId && connection.pinIds.includes(pinId)
|
|
15114
15339
|
);
|
|
15115
15340
|
}
|
|
15341
|
+
getMultiPinNetConnection(label) {
|
|
15342
|
+
if (!label.netId || label.pinIds.length !== 1) return void 0;
|
|
15343
|
+
const pinId = label.pinIds[0];
|
|
15344
|
+
return this.inputProblem.netConnections.find(
|
|
15345
|
+
(connection) => connection.isGround === false && connection.pinIds.length > 2 && connection.netId === label.netId && connection.pinIds.includes(pinId)
|
|
15346
|
+
);
|
|
15347
|
+
}
|
|
15116
15348
|
buildCandidatePairs() {
|
|
15117
15349
|
const { netConnMap } = getConnectivityMapsFromInputProblem(
|
|
15118
15350
|
this.inputProblem
|
|
15119
15351
|
);
|
|
15120
|
-
const
|
|
15352
|
+
const groundGlobalConnNetIds = /* @__PURE__ */ new Set();
|
|
15353
|
+
for (const connection of this.inputProblem.netConnections) {
|
|
15354
|
+
if (!connection.isGround) continue;
|
|
15355
|
+
const globalConnNetId = netConnMap.getNetConnectedToId(connection.netId);
|
|
15356
|
+
if (globalConnNetId) groundGlobalConnNetIds.add(globalConnNetId);
|
|
15357
|
+
}
|
|
15121
15358
|
const labelsByGlobalNet = /* @__PURE__ */ new Map();
|
|
15122
15359
|
for (const label of this.input.netLabelPlacements) {
|
|
15123
|
-
if (!this.
|
|
15124
|
-
label,
|
|
15125
|
-
groundGlobalConnNetId
|
|
15126
|
-
)) {
|
|
15360
|
+
if (!this.isPortOnlyFallbackLabel(label, groundGlobalConnNetIds) || !this.isDirectConnectionLabel(label) && !this.getMultiPinNetConnection(label)) {
|
|
15127
15361
|
continue;
|
|
15128
15362
|
}
|
|
15129
15363
|
const labels = labelsByGlobalNet.get(label.globalConnNetId) ?? [];
|
|
@@ -15139,6 +15373,16 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
15139
15373
|
const firstPin = this.pinMap.get(firstLabel.pinIds[0]);
|
|
15140
15374
|
const secondPin = this.pinMap.get(secondLabel.pinIds[0]);
|
|
15141
15375
|
if (!firstPin || !secondPin) continue;
|
|
15376
|
+
const perpendicularOffset = getPerpendicularOffset(
|
|
15377
|
+
firstPin,
|
|
15378
|
+
secondPin
|
|
15379
|
+
);
|
|
15380
|
+
const bothLabelsBelongToDirectConnections = this.isDirectConnectionLabel(firstLabel) && this.isDirectConnectionLabel(secondLabel);
|
|
15381
|
+
const firstMultiPinNetConnection = this.getMultiPinNetConnection(firstLabel);
|
|
15382
|
+
const secondMultiPinNetConnection = this.getMultiPinNetConnection(secondLabel);
|
|
15383
|
+
if (!bothLabelsBelongToDirectConnections && (!firstMultiPinNetConnection || firstMultiPinNetConnection !== secondMultiPinNetConnection || perpendicularOffset > MAX_NAMED_NET_RECOVERY_PERPENDICULAR_OFFSET)) {
|
|
15384
|
+
continue;
|
|
15385
|
+
}
|
|
15142
15386
|
if (arePinsInDifferentSchematicSections(
|
|
15143
15387
|
this.inputProblem,
|
|
15144
15388
|
firstPin,
|
|
@@ -15159,18 +15403,103 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
15159
15403
|
firstLabel,
|
|
15160
15404
|
secondLabel,
|
|
15161
15405
|
pins: [firstPin, secondPin],
|
|
15162
|
-
perpendicularOffset
|
|
15406
|
+
perpendicularOffset,
|
|
15163
15407
|
routeDistance: Math.abs(firstPin.x - secondPin.x) + Math.abs(firstPin.y - secondPin.y),
|
|
15164
|
-
key: getCanonicalPairKey(firstPin.pinId, secondPin.pinId)
|
|
15408
|
+
key: getCanonicalPairKey(firstPin.pinId, secondPin.pinId),
|
|
15409
|
+
recoveryMode: "fallback_labels"
|
|
15165
15410
|
});
|
|
15166
15411
|
}
|
|
15167
15412
|
}
|
|
15168
15413
|
}
|
|
15414
|
+
candidates.push(...this.buildRoutedComponentCandidates());
|
|
15169
15415
|
candidates.sort(
|
|
15170
15416
|
(first, second) => first.perpendicularOffset - second.perpendicularOffset || first.routeDistance - second.routeDistance || first.key.localeCompare(second.key)
|
|
15171
15417
|
);
|
|
15172
15418
|
return candidates;
|
|
15173
15419
|
}
|
|
15420
|
+
buildRoutedComponentCandidates() {
|
|
15421
|
+
const { netConnMap } = getConnectivityMapsFromInputProblem(
|
|
15422
|
+
this.inputProblem
|
|
15423
|
+
);
|
|
15424
|
+
const candidates = [];
|
|
15425
|
+
for (const connection of this.inputProblem.netConnections) {
|
|
15426
|
+
if (connection.pinIds.length <= 2 || connection.isGround !== false)
|
|
15427
|
+
continue;
|
|
15428
|
+
const globalConnNetId = netConnMap.getNetConnectedToId(connection.netId);
|
|
15429
|
+
if (!globalConnNetId) continue;
|
|
15430
|
+
const traceConnectedPinComponents = getTraceConnectedPinComponents({
|
|
15431
|
+
pinIds: connection.pinIds,
|
|
15432
|
+
traces: this.outputTraces.filter(
|
|
15433
|
+
(trace) => trace.globalConnNetId === globalConnNetId
|
|
15434
|
+
)
|
|
15435
|
+
}).filter((component) => component.traces.length > 0);
|
|
15436
|
+
for (let firstIndex = 0; firstIndex < traceConnectedPinComponents.length; firstIndex++) {
|
|
15437
|
+
for (let secondIndex = firstIndex + 1; secondIndex < traceConnectedPinComponents.length; secondIndex++) {
|
|
15438
|
+
const firstComponent = traceConnectedPinComponents[firstIndex];
|
|
15439
|
+
const secondComponent = traceConnectedPinComponents[secondIndex];
|
|
15440
|
+
const firstLabel = this.input.netLabelPlacements.find(
|
|
15441
|
+
(label) => label.globalConnNetId === globalConnNetId && label.mspConnectionPairIds.length > 0 && label.pinIds.some(
|
|
15442
|
+
(pinId) => firstComponent.pinIds.includes(pinId)
|
|
15443
|
+
)
|
|
15444
|
+
);
|
|
15445
|
+
const secondLabel = this.input.netLabelPlacements.find(
|
|
15446
|
+
(label) => label.globalConnNetId === globalConnNetId && label.mspConnectionPairIds.length > 0 && label.pinIds.some(
|
|
15447
|
+
(pinId) => secondComponent.pinIds.includes(pinId)
|
|
15448
|
+
)
|
|
15449
|
+
);
|
|
15450
|
+
if (!firstLabel || !secondLabel || firstLabel === secondLabel)
|
|
15451
|
+
continue;
|
|
15452
|
+
if (getPerpendicularOffset(
|
|
15453
|
+
firstLabel.anchorPoint,
|
|
15454
|
+
secondLabel.anchorPoint
|
|
15455
|
+
) > MAX_ROUTED_COMPONENT_RECOVERY_PERPENDICULAR_OFFSET) {
|
|
15456
|
+
continue;
|
|
15457
|
+
}
|
|
15458
|
+
let bestCandidate;
|
|
15459
|
+
for (const firstPinId of firstComponent.pinIds) {
|
|
15460
|
+
for (const secondPinId of secondComponent.pinIds) {
|
|
15461
|
+
const firstPin = this.pinMap.get(firstPinId);
|
|
15462
|
+
const secondPin = this.pinMap.get(secondPinId);
|
|
15463
|
+
if (!firstPin || !secondPin) continue;
|
|
15464
|
+
const perpendicularOffset = getPerpendicularOffset(
|
|
15465
|
+
firstPin,
|
|
15466
|
+
secondPin
|
|
15467
|
+
);
|
|
15468
|
+
if (perpendicularOffset > MAX_ROUTED_COMPONENT_RECOVERY_PERPENDICULAR_OFFSET || arePinsCoFacingAlongSeparationAxis(firstPin, secondPin) || arePinsInDifferentSchematicSections(
|
|
15469
|
+
this.inputProblem,
|
|
15470
|
+
firstPin,
|
|
15471
|
+
secondPin
|
|
15472
|
+
) || doesPairCrossRestrictedCenterLines({
|
|
15473
|
+
inputProblem: this.inputProblem,
|
|
15474
|
+
chipMap: this.chipMap,
|
|
15475
|
+
pinIdMap: this.pinMap,
|
|
15476
|
+
p1: firstPin,
|
|
15477
|
+
p2: secondPin
|
|
15478
|
+
})) {
|
|
15479
|
+
continue;
|
|
15480
|
+
}
|
|
15481
|
+
const routeDistance = Math.abs(firstPin.x - secondPin.x) + Math.abs(firstPin.y - secondPin.y);
|
|
15482
|
+
const candidate = {
|
|
15483
|
+
firstLabel,
|
|
15484
|
+
secondLabel,
|
|
15485
|
+
pins: [firstPin, secondPin],
|
|
15486
|
+
perpendicularOffset,
|
|
15487
|
+
routeDistance,
|
|
15488
|
+
key: getCanonicalPairKey(firstPin.pinId, secondPin.pinId),
|
|
15489
|
+
recoveryMode: "routed_components",
|
|
15490
|
+
netConnectionPinIds: connection.pinIds
|
|
15491
|
+
};
|
|
15492
|
+
if (!bestCandidate || candidate.routeDistance < bestCandidate.routeDistance || candidate.routeDistance === bestCandidate.routeDistance && (candidate.perpendicularOffset < bestCandidate.perpendicularOffset || candidate.perpendicularOffset === bestCandidate.perpendicularOffset && candidate.key.localeCompare(bestCandidate.key) < 0)) {
|
|
15493
|
+
bestCandidate = candidate;
|
|
15494
|
+
}
|
|
15495
|
+
}
|
|
15496
|
+
}
|
|
15497
|
+
if (bestCandidate) candidates.push(bestCandidate);
|
|
15498
|
+
}
|
|
15499
|
+
}
|
|
15500
|
+
}
|
|
15501
|
+
return candidates;
|
|
15502
|
+
}
|
|
15174
15503
|
isSupersededConnectorTrace(trace, candidate) {
|
|
15175
15504
|
if (!trace.mspPairId.startsWith(AVAILABLE_NET_ORIENTATION_PREFIX)) {
|
|
15176
15505
|
return false;
|
|
@@ -15196,7 +15525,13 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
15196
15525
|
const retainedTraces = this.outputTraces.filter(
|
|
15197
15526
|
(trace) => !this.isSupersededConnectorTrace(trace, candidate)
|
|
15198
15527
|
);
|
|
15199
|
-
|
|
15528
|
+
let collisionTraces = retainedTraces;
|
|
15529
|
+
if (candidate.recoveryMode === "routed_components") {
|
|
15530
|
+
collisionTraces = retainedTraces.filter(
|
|
15531
|
+
(trace) => trace.globalConnNetId !== candidate.firstLabel.globalConnNetId
|
|
15532
|
+
);
|
|
15533
|
+
}
|
|
15534
|
+
if (doesTraceOverlapWithExistingTraces(tracePath, collisionTraces) || this.routeIntersectsRemainingLabels(tracePath, candidate)) {
|
|
15200
15535
|
return;
|
|
15201
15536
|
}
|
|
15202
15537
|
const [firstPin, secondPin] = candidate.pins;
|
|
@@ -15211,11 +15546,22 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
15211
15546
|
pinIds: [firstPin.pinId, secondPin.pinId]
|
|
15212
15547
|
};
|
|
15213
15548
|
this.outputTraces = [...retainedTraces, recoveredTrace];
|
|
15214
|
-
|
|
15215
|
-
|
|
15216
|
-
|
|
15549
|
+
if (candidate.recoveryMode === "fallback_labels") {
|
|
15550
|
+
this.outputNetLabelPlacements = this.outputNetLabelPlacements.filter(
|
|
15551
|
+
(label) => label !== candidate.firstLabel && label !== candidate.secondLabel
|
|
15552
|
+
);
|
|
15553
|
+
}
|
|
15217
15554
|
this.stats.recoveredTraceCount++;
|
|
15218
15555
|
}
|
|
15556
|
+
areCandidatePinsAlreadyConnected(candidate) {
|
|
15557
|
+
if (!candidate.netConnectionPinIds) return false;
|
|
15558
|
+
return getTraceConnectedPinComponents({
|
|
15559
|
+
pinIds: candidate.netConnectionPinIds,
|
|
15560
|
+
traces: this.outputTraces
|
|
15561
|
+
}).some(
|
|
15562
|
+
(component) => component.pinIds.includes(candidate.pins[0].pinId) && component.pinIds.includes(candidate.pins[1].pinId)
|
|
15563
|
+
);
|
|
15564
|
+
}
|
|
15219
15565
|
_step() {
|
|
15220
15566
|
if (this.activeSubSolver) {
|
|
15221
15567
|
this.activeSubSolver.step();
|
|
@@ -15230,7 +15576,7 @@ var NetLabelToTraceSolver = class extends BaseSolver {
|
|
|
15230
15576
|
return;
|
|
15231
15577
|
}
|
|
15232
15578
|
let candidate = this.queuedCandidates.shift();
|
|
15233
|
-
while (candidate && (!this.outputNetLabelPlacements.includes(candidate.firstLabel) || !this.outputNetLabelPlacements.includes(candidate.secondLabel))) {
|
|
15579
|
+
while (candidate && (!this.outputNetLabelPlacements.includes(candidate.firstLabel) || !this.outputNetLabelPlacements.includes(candidate.secondLabel) || this.areCandidatePinsAlreadyConnected(candidate))) {
|
|
15234
15580
|
candidate = this.queuedCandidates.shift();
|
|
15235
15581
|
}
|
|
15236
15582
|
if (!candidate) {
|