@tscircuit/schematic-trace-solver 0.0.189 → 0.0.190
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.js +252 -223
- package/lib/solvers/SameNetJunctionAlignmentSolver/SameNetJunctionAlignmentSolver.ts +4 -9
- package/lib/solvers/SameNetJunctionAlignmentSolver/alignSameNetJunctions.ts +10 -2
- package/lib/solvers/SameNetJunctionAlignmentSolver/collapseSameNetCycles.ts +75 -38
- package/package.json +1 -1
- package/tests/repros/__snapshots__/repro-pmp11282-isolated-dcdc.snap.svg +18 -18
- package/tests/repros/__snapshots__/repro-repeated-power-rail-junctions.snap.svg +255 -0
- package/tests/repros/assets/repro-repeated-power-rail-junctions.input.json +927 -0
- package/tests/repros/repro-repeated-power-rail-junctions.test.ts +22 -0
- package/tests/solvers/SameNetJunctionAlignmentSolver/collapse-same-net-cycles.test.ts +30 -0
package/dist/index.js
CHANGED
|
@@ -13275,7 +13275,7 @@ var UnroutedTraceRecoverySolver = class extends BaseSolver {
|
|
|
13275
13275
|
};
|
|
13276
13276
|
|
|
13277
13277
|
// lib/solvers/SameNetJunctionAlignmentSolver/alignSameNetJunctions.ts
|
|
13278
|
-
import { getSegmentIntersection as
|
|
13278
|
+
import { getSegmentIntersection as getSegmentIntersection4 } from "@tscircuit/math-utils/line-intersections";
|
|
13279
13279
|
|
|
13280
13280
|
// lib/solvers/SameNetJunctionAlignmentSolver/pathIntersectsAnyNetLabel.ts
|
|
13281
13281
|
var NET_LABEL_INTERIOR_INSET = 1e-6;
|
|
@@ -13594,6 +13594,242 @@ var collapseRedundantSharedEndpointStubs = ({
|
|
|
13594
13594
|
return outputTraces;
|
|
13595
13595
|
};
|
|
13596
13596
|
|
|
13597
|
+
// lib/solvers/SameNetJunctionAlignmentSolver/collapseSameNetCycles.ts
|
|
13598
|
+
import { getSegmentIntersection as getSegmentIntersection3 } from "@tscircuit/math-utils/line-intersections";
|
|
13599
|
+
var TRACE_LENGTH_EPSILON = 1e-6;
|
|
13600
|
+
var getTracePathStartingAtPin = (trace, pin) => {
|
|
13601
|
+
const pathStart = trace.tracePath[0];
|
|
13602
|
+
const pathEnd = trace.tracePath.at(-1);
|
|
13603
|
+
if (!pathStart || !pathEnd) return null;
|
|
13604
|
+
if (pointsEqual2(pathStart, pin)) return trace.tracePath;
|
|
13605
|
+
if (pointsEqual2(pathEnd, pin)) return [...trace.tracePath].reverse();
|
|
13606
|
+
return null;
|
|
13607
|
+
};
|
|
13608
|
+
var getPerpendicularPathCrossings = (targetPath, donorPath) => {
|
|
13609
|
+
const crossings = [];
|
|
13610
|
+
const sharedEndpoint = targetPath[0];
|
|
13611
|
+
for (let targetSegmentIndex = 0; targetSegmentIndex < targetPath.length - 1; targetSegmentIndex++) {
|
|
13612
|
+
const targetStart = targetPath[targetSegmentIndex];
|
|
13613
|
+
const targetEnd = targetPath[targetSegmentIndex + 1];
|
|
13614
|
+
const targetOrientation = getRailOrientation(targetStart, targetEnd);
|
|
13615
|
+
if (!targetOrientation) continue;
|
|
13616
|
+
for (let donorSegmentIndex = 0; donorSegmentIndex < donorPath.length - 1; donorSegmentIndex++) {
|
|
13617
|
+
const donorStart = donorPath[donorSegmentIndex];
|
|
13618
|
+
const donorEnd = donorPath[donorSegmentIndex + 1];
|
|
13619
|
+
const donorOrientation = getRailOrientation(donorStart, donorEnd);
|
|
13620
|
+
if (!donorOrientation || donorOrientation === targetOrientation) continue;
|
|
13621
|
+
const intersectionPoint = getSegmentIntersection3(
|
|
13622
|
+
targetStart,
|
|
13623
|
+
targetEnd,
|
|
13624
|
+
donorStart,
|
|
13625
|
+
donorEnd
|
|
13626
|
+
);
|
|
13627
|
+
if (!intersectionPoint || pointsEqual2(intersectionPoint, sharedEndpoint)) {
|
|
13628
|
+
continue;
|
|
13629
|
+
}
|
|
13630
|
+
crossings.push({
|
|
13631
|
+
intersectionPoint,
|
|
13632
|
+
targetSegmentIndex,
|
|
13633
|
+
donorSegmentIndex
|
|
13634
|
+
});
|
|
13635
|
+
}
|
|
13636
|
+
}
|
|
13637
|
+
return crossings;
|
|
13638
|
+
};
|
|
13639
|
+
var buildCollapsedSelfCyclePath = (path, firstSegmentIndex, secondSegmentIndex) => {
|
|
13640
|
+
const intersectionPoint = getSegmentIntersection3(
|
|
13641
|
+
path[firstSegmentIndex],
|
|
13642
|
+
path[firstSegmentIndex + 1],
|
|
13643
|
+
path[secondSegmentIndex],
|
|
13644
|
+
path[secondSegmentIndex + 1]
|
|
13645
|
+
);
|
|
13646
|
+
if (!intersectionPoint) return path;
|
|
13647
|
+
return simplifyPath([
|
|
13648
|
+
...path.slice(0, firstSegmentIndex + 1),
|
|
13649
|
+
intersectionPoint,
|
|
13650
|
+
...path.slice(secondSegmentIndex + 1)
|
|
13651
|
+
]);
|
|
13652
|
+
};
|
|
13653
|
+
var buildCollapsedCyclePath = ({
|
|
13654
|
+
targetTrace,
|
|
13655
|
+
targetPath,
|
|
13656
|
+
donorPath,
|
|
13657
|
+
crossing
|
|
13658
|
+
}) => {
|
|
13659
|
+
const pathFromSharedPin = simplifyPath([
|
|
13660
|
+
...donorPath.slice(0, crossing.donorSegmentIndex + 1),
|
|
13661
|
+
crossing.intersectionPoint,
|
|
13662
|
+
...targetPath.slice(crossing.targetSegmentIndex + 1)
|
|
13663
|
+
]);
|
|
13664
|
+
if (pointsEqual2(targetTrace.tracePath[0], targetPath[0])) {
|
|
13665
|
+
return pathFromSharedPin;
|
|
13666
|
+
}
|
|
13667
|
+
return pathFromSharedPin.reverse();
|
|
13668
|
+
};
|
|
13669
|
+
var getNetLabelPlacementsForCycleCollapse = ({
|
|
13670
|
+
targetTrace,
|
|
13671
|
+
tracePath,
|
|
13672
|
+
netLabelPlacements
|
|
13673
|
+
}) => {
|
|
13674
|
+
const candidateNetLabelPlacements = moveAttachedLabelsToReroutedTrace({
|
|
13675
|
+
trace: targetTrace,
|
|
13676
|
+
originalTracePath: targetTrace.tracePath,
|
|
13677
|
+
reroutedTracePath: tracePath,
|
|
13678
|
+
netLabelPlacements
|
|
13679
|
+
});
|
|
13680
|
+
for (let labelIndex = 0; labelIndex < netLabelPlacements.length; labelIndex++) {
|
|
13681
|
+
const label = netLabelPlacements[labelIndex];
|
|
13682
|
+
if (label.globalConnNetId !== targetTrace.globalConnNetId) continue;
|
|
13683
|
+
if (!tracePathContainsPoint(targetTrace.tracePath, label.anchorPoint)) {
|
|
13684
|
+
continue;
|
|
13685
|
+
}
|
|
13686
|
+
const candidateLabel = candidateNetLabelPlacements[labelIndex];
|
|
13687
|
+
if (!tracePathContainsPoint(tracePath, candidateLabel.anchorPoint)) {
|
|
13688
|
+
return null;
|
|
13689
|
+
}
|
|
13690
|
+
}
|
|
13691
|
+
const otherNetLabelPlacements = candidateNetLabelPlacements.filter(
|
|
13692
|
+
(label) => label.globalConnNetId !== targetTrace.globalConnNetId
|
|
13693
|
+
);
|
|
13694
|
+
if (pathIntersectsAnyNetLabel({
|
|
13695
|
+
path: tracePath,
|
|
13696
|
+
netLabelPlacements: otherNetLabelPlacements
|
|
13697
|
+
})) {
|
|
13698
|
+
return null;
|
|
13699
|
+
}
|
|
13700
|
+
const sameNetLabelPlacements = candidateNetLabelPlacements.filter(
|
|
13701
|
+
(label) => label.globalConnNetId === targetTrace.globalConnNetId
|
|
13702
|
+
);
|
|
13703
|
+
if (pathEntersAnyNetLabel({
|
|
13704
|
+
path: tracePath,
|
|
13705
|
+
netLabelPlacements: sameNetLabelPlacements
|
|
13706
|
+
})) {
|
|
13707
|
+
return null;
|
|
13708
|
+
}
|
|
13709
|
+
return candidateNetLabelPlacements;
|
|
13710
|
+
};
|
|
13711
|
+
var candidateIsBetter = (candidate, bestCandidate) => {
|
|
13712
|
+
if (!bestCandidate) return true;
|
|
13713
|
+
const visibleLengthDelta = candidate.netVisibleLength - bestCandidate.netVisibleLength;
|
|
13714
|
+
if (Math.abs(visibleLengthDelta) > TRACE_LENGTH_EPSILON) {
|
|
13715
|
+
return visibleLengthDelta < 0;
|
|
13716
|
+
}
|
|
13717
|
+
return candidate.netVisibleSegmentCount < bestCandidate.netVisibleSegmentCount;
|
|
13718
|
+
};
|
|
13719
|
+
var getBestCycleCollapseCandidate = ({
|
|
13720
|
+
targetTrace,
|
|
13721
|
+
traces,
|
|
13722
|
+
netLabelPlacements
|
|
13723
|
+
}) => {
|
|
13724
|
+
const sameNetTraces = traces.filter(
|
|
13725
|
+
(trace) => trace.globalConnNetId === targetTrace.globalConnNetId
|
|
13726
|
+
);
|
|
13727
|
+
const baselineNetVisibleLength = getVisibleTraceLength(sameNetTraces);
|
|
13728
|
+
const baselineTargetVisibleLength = getVisibleTraceLength([targetTrace]);
|
|
13729
|
+
let bestCandidate = null;
|
|
13730
|
+
const considerTracePath = (tracePath) => {
|
|
13731
|
+
const candidateTrace = { ...targetTrace, tracePath };
|
|
13732
|
+
const candidateTargetVisibleLength = getVisibleTraceLength([candidateTrace]);
|
|
13733
|
+
if (candidateTargetVisibleLength > baselineTargetVisibleLength + TRACE_LENGTH_EPSILON) {
|
|
13734
|
+
return;
|
|
13735
|
+
}
|
|
13736
|
+
const candidateNetLabelPlacements = getNetLabelPlacementsForCycleCollapse({
|
|
13737
|
+
targetTrace,
|
|
13738
|
+
tracePath,
|
|
13739
|
+
netLabelPlacements
|
|
13740
|
+
});
|
|
13741
|
+
if (!candidateNetLabelPlacements) return;
|
|
13742
|
+
const candidateNetTraces = sameNetTraces.map((trace) => {
|
|
13743
|
+
if (trace.mspPairId === targetTrace.mspPairId) return candidateTrace;
|
|
13744
|
+
return trace;
|
|
13745
|
+
});
|
|
13746
|
+
const netVisibleLength = getVisibleTraceLength(candidateNetTraces);
|
|
13747
|
+
if (netVisibleLength >= baselineNetVisibleLength - TRACE_LENGTH_EPSILON) {
|
|
13748
|
+
return;
|
|
13749
|
+
}
|
|
13750
|
+
const candidate = {
|
|
13751
|
+
tracePath,
|
|
13752
|
+
netLabelPlacements: candidateNetLabelPlacements,
|
|
13753
|
+
netVisibleLength,
|
|
13754
|
+
netVisibleSegmentCount: getVisibleTraceSegmentCount(candidateNetTraces)
|
|
13755
|
+
};
|
|
13756
|
+
if (candidateIsBetter(candidate, bestCandidate)) {
|
|
13757
|
+
bestCandidate = candidate;
|
|
13758
|
+
}
|
|
13759
|
+
};
|
|
13760
|
+
const selfCrossings = findPerpendicularPathCrossings(
|
|
13761
|
+
targetTrace.tracePath,
|
|
13762
|
+
targetTrace.tracePath,
|
|
13763
|
+
{ includeTerminalSegments: true }
|
|
13764
|
+
).filter(
|
|
13765
|
+
({ pathSegmentIndex, otherPathSegmentIndex }) => pathSegmentIndex < otherPathSegmentIndex
|
|
13766
|
+
);
|
|
13767
|
+
for (const crossing of selfCrossings) {
|
|
13768
|
+
considerTracePath(
|
|
13769
|
+
buildCollapsedSelfCyclePath(
|
|
13770
|
+
targetTrace.tracePath,
|
|
13771
|
+
crossing.pathSegmentIndex,
|
|
13772
|
+
crossing.otherPathSegmentIndex
|
|
13773
|
+
)
|
|
13774
|
+
);
|
|
13775
|
+
}
|
|
13776
|
+
for (const donorTrace of sameNetTraces) {
|
|
13777
|
+
if (donorTrace.mspPairId === targetTrace.mspPairId) continue;
|
|
13778
|
+
const sharedPin = getSharedPin({
|
|
13779
|
+
donorTrace,
|
|
13780
|
+
branchTrace: targetTrace
|
|
13781
|
+
});
|
|
13782
|
+
if (!sharedPin) continue;
|
|
13783
|
+
const targetPath = getTracePathStartingAtPin(targetTrace, sharedPin);
|
|
13784
|
+
const donorPath = getTracePathStartingAtPin(donorTrace, sharedPin);
|
|
13785
|
+
if (!targetPath || !donorPath) continue;
|
|
13786
|
+
const crossings = getPerpendicularPathCrossings(targetPath, donorPath);
|
|
13787
|
+
for (const crossing of crossings) {
|
|
13788
|
+
const tracePath = buildCollapsedCyclePath({
|
|
13789
|
+
targetTrace,
|
|
13790
|
+
targetPath,
|
|
13791
|
+
donorPath,
|
|
13792
|
+
crossing
|
|
13793
|
+
});
|
|
13794
|
+
considerTracePath(tracePath);
|
|
13795
|
+
}
|
|
13796
|
+
}
|
|
13797
|
+
return bestCandidate;
|
|
13798
|
+
};
|
|
13799
|
+
var collapseSameNetCycles = ({
|
|
13800
|
+
traces,
|
|
13801
|
+
netLabelPlacements
|
|
13802
|
+
}) => {
|
|
13803
|
+
const outputTraces = [...traces];
|
|
13804
|
+
let outputNetLabelPlacements = [...netLabelPlacements];
|
|
13805
|
+
let collapsedCycleCount = 0;
|
|
13806
|
+
let traceIndex = 0;
|
|
13807
|
+
while (traceIndex < outputTraces.length) {
|
|
13808
|
+
const targetTrace = outputTraces[traceIndex];
|
|
13809
|
+
const candidate = getBestCycleCollapseCandidate({
|
|
13810
|
+
targetTrace,
|
|
13811
|
+
traces: outputTraces,
|
|
13812
|
+
netLabelPlacements: outputNetLabelPlacements
|
|
13813
|
+
});
|
|
13814
|
+
if (!candidate) {
|
|
13815
|
+
traceIndex++;
|
|
13816
|
+
continue;
|
|
13817
|
+
}
|
|
13818
|
+
outputTraces[traceIndex] = {
|
|
13819
|
+
...targetTrace,
|
|
13820
|
+
tracePath: candidate.tracePath
|
|
13821
|
+
};
|
|
13822
|
+
outputNetLabelPlacements = candidate.netLabelPlacements;
|
|
13823
|
+
collapsedCycleCount++;
|
|
13824
|
+
traceIndex = 0;
|
|
13825
|
+
}
|
|
13826
|
+
return {
|
|
13827
|
+
traces: outputTraces,
|
|
13828
|
+
netLabelPlacements: outputNetLabelPlacements,
|
|
13829
|
+
collapsedCycleCount
|
|
13830
|
+
};
|
|
13831
|
+
};
|
|
13832
|
+
|
|
13597
13833
|
// lib/solvers/SameNetJunctionAlignmentSolver/alignSameNetJunctions.ts
|
|
13598
13834
|
var MAX_ALIGNED_LOAD_PIN_OFFSET = 0.2;
|
|
13599
13835
|
var MAX_SAME_NET_LABEL_BOUNDARY_RAIL_OFFSET = 0.2;
|
|
@@ -13978,7 +14214,7 @@ var pathsIntersect = (firstPath, secondPath) => {
|
|
|
13978
14214
|
}
|
|
13979
14215
|
for (let firstIndex = 1; firstIndex < firstPath.length; firstIndex++) {
|
|
13980
14216
|
for (let secondIndex = 1; secondIndex < secondPath.length; secondIndex++) {
|
|
13981
|
-
if (
|
|
14217
|
+
if (getSegmentIntersection4(
|
|
13982
14218
|
firstPath[firstIndex - 1],
|
|
13983
14219
|
firstPath[firstIndex],
|
|
13984
14220
|
secondPath[secondIndex - 1],
|
|
@@ -14162,7 +14398,7 @@ var candidateIsClear = ({
|
|
|
14162
14398
|
const intersections2 = /* @__PURE__ */ new Set();
|
|
14163
14399
|
for (let i = 1; i < path.length; i++) {
|
|
14164
14400
|
for (let j = 1; j < otherTrace.tracePath.length; j++) {
|
|
14165
|
-
const point =
|
|
14401
|
+
const point = getSegmentIntersection4(
|
|
14166
14402
|
path[i - 1],
|
|
14167
14403
|
path[i],
|
|
14168
14404
|
otherTrace.tracePath[j - 1],
|
|
@@ -14445,225 +14681,22 @@ var alignSameNetJunctions = ({
|
|
|
14445
14681
|
}
|
|
14446
14682
|
}
|
|
14447
14683
|
}
|
|
14448
|
-
const
|
|
14684
|
+
const cycleCollapse = collapseSameNetCycles({
|
|
14449
14685
|
traces: outputTraces,
|
|
14450
|
-
netLabelPlacements: outputNetLabelPlacements
|
|
14686
|
+
netLabelPlacements: outputNetLabelPlacements
|
|
14687
|
+
});
|
|
14688
|
+
outputTraces = collapseRedundantSharedEndpointStubs({
|
|
14689
|
+
traces: cycleCollapse.traces,
|
|
14690
|
+
netLabelPlacements: cycleCollapse.netLabelPlacements,
|
|
14451
14691
|
netLabelConnectorTraceIds,
|
|
14452
14692
|
multiPinNetPinIds: getMultiPinNetPinIds(inputProblem)
|
|
14453
14693
|
});
|
|
14454
|
-
|
|
14455
|
-
return {
|
|
14456
|
-
traces: outputTraces,
|
|
14457
|
-
netLabelPlacements: outputNetLabelPlacements,
|
|
14458
|
-
alignedJunctionCount
|
|
14459
|
-
};
|
|
14460
|
-
};
|
|
14461
|
-
|
|
14462
|
-
// lib/solvers/SameNetJunctionAlignmentSolver/collapseSameNetCycles.ts
|
|
14463
|
-
import { getSegmentIntersection as getSegmentIntersection4 } from "@tscircuit/math-utils/line-intersections";
|
|
14464
|
-
var TRACE_LENGTH_EPSILON = 1e-6;
|
|
14465
|
-
var getTracePathStartingAtPin = (trace, pin) => {
|
|
14466
|
-
const pathStart = trace.tracePath[0];
|
|
14467
|
-
const pathEnd = trace.tracePath.at(-1);
|
|
14468
|
-
if (!pathStart || !pathEnd) return null;
|
|
14469
|
-
if (pointsEqual2(pathStart, pin)) return trace.tracePath;
|
|
14470
|
-
if (pointsEqual2(pathEnd, pin)) return [...trace.tracePath].reverse();
|
|
14471
|
-
return null;
|
|
14472
|
-
};
|
|
14473
|
-
var getPerpendicularPathCrossings = (targetPath, donorPath) => {
|
|
14474
|
-
const crossings = [];
|
|
14475
|
-
const sharedEndpoint = targetPath[0];
|
|
14476
|
-
for (let targetSegmentIndex = 0; targetSegmentIndex < targetPath.length - 1; targetSegmentIndex++) {
|
|
14477
|
-
const targetStart = targetPath[targetSegmentIndex];
|
|
14478
|
-
const targetEnd = targetPath[targetSegmentIndex + 1];
|
|
14479
|
-
const targetOrientation = getRailOrientation(targetStart, targetEnd);
|
|
14480
|
-
if (!targetOrientation) continue;
|
|
14481
|
-
for (let donorSegmentIndex = 0; donorSegmentIndex < donorPath.length - 1; donorSegmentIndex++) {
|
|
14482
|
-
const donorStart = donorPath[donorSegmentIndex];
|
|
14483
|
-
const donorEnd = donorPath[donorSegmentIndex + 1];
|
|
14484
|
-
const donorOrientation = getRailOrientation(donorStart, donorEnd);
|
|
14485
|
-
if (!donorOrientation || donorOrientation === targetOrientation) continue;
|
|
14486
|
-
const intersectionPoint = getSegmentIntersection4(
|
|
14487
|
-
targetStart,
|
|
14488
|
-
targetEnd,
|
|
14489
|
-
donorStart,
|
|
14490
|
-
donorEnd
|
|
14491
|
-
);
|
|
14492
|
-
if (!intersectionPoint || pointsEqual2(intersectionPoint, sharedEndpoint)) {
|
|
14493
|
-
continue;
|
|
14494
|
-
}
|
|
14495
|
-
crossings.push({
|
|
14496
|
-
intersectionPoint,
|
|
14497
|
-
targetSegmentIndex,
|
|
14498
|
-
donorSegmentIndex
|
|
14499
|
-
});
|
|
14500
|
-
}
|
|
14501
|
-
}
|
|
14502
|
-
return crossings;
|
|
14503
|
-
};
|
|
14504
|
-
var buildCollapsedCyclePath = ({
|
|
14505
|
-
targetTrace,
|
|
14506
|
-
targetPath,
|
|
14507
|
-
donorPath,
|
|
14508
|
-
crossing
|
|
14509
|
-
}) => {
|
|
14510
|
-
const pathFromSharedPin = simplifyPath([
|
|
14511
|
-
...donorPath.slice(0, crossing.donorSegmentIndex + 1),
|
|
14512
|
-
crossing.intersectionPoint,
|
|
14513
|
-
...targetPath.slice(crossing.targetSegmentIndex + 1)
|
|
14514
|
-
]);
|
|
14515
|
-
if (pointsEqual2(targetTrace.tracePath[0], targetPath[0])) {
|
|
14516
|
-
return pathFromSharedPin;
|
|
14517
|
-
}
|
|
14518
|
-
return pathFromSharedPin.reverse();
|
|
14519
|
-
};
|
|
14520
|
-
var getNetLabelPlacementsForCycleCollapse = ({
|
|
14521
|
-
targetTrace,
|
|
14522
|
-
tracePath,
|
|
14523
|
-
netLabelPlacements
|
|
14524
|
-
}) => {
|
|
14525
|
-
const candidateNetLabelPlacements = moveAttachedLabelsToReroutedTrace({
|
|
14526
|
-
trace: targetTrace,
|
|
14527
|
-
originalTracePath: targetTrace.tracePath,
|
|
14528
|
-
reroutedTracePath: tracePath,
|
|
14529
|
-
netLabelPlacements
|
|
14530
|
-
});
|
|
14531
|
-
for (let labelIndex = 0; labelIndex < netLabelPlacements.length; labelIndex++) {
|
|
14532
|
-
const label = netLabelPlacements[labelIndex];
|
|
14533
|
-
if (label.globalConnNetId !== targetTrace.globalConnNetId) continue;
|
|
14534
|
-
if (!tracePathContainsPoint(targetTrace.tracePath, label.anchorPoint)) {
|
|
14535
|
-
continue;
|
|
14536
|
-
}
|
|
14537
|
-
const candidateLabel = candidateNetLabelPlacements[labelIndex];
|
|
14538
|
-
if (!tracePathContainsPoint(tracePath, candidateLabel.anchorPoint)) {
|
|
14539
|
-
return null;
|
|
14540
|
-
}
|
|
14541
|
-
}
|
|
14542
|
-
const otherNetLabelPlacements = candidateNetLabelPlacements.filter(
|
|
14543
|
-
(label) => label.globalConnNetId !== targetTrace.globalConnNetId
|
|
14544
|
-
);
|
|
14545
|
-
if (pathIntersectsAnyNetLabel({
|
|
14546
|
-
path: tracePath,
|
|
14547
|
-
netLabelPlacements: otherNetLabelPlacements
|
|
14548
|
-
})) {
|
|
14549
|
-
return null;
|
|
14550
|
-
}
|
|
14551
|
-
const sameNetLabelPlacements = candidateNetLabelPlacements.filter(
|
|
14552
|
-
(label) => label.globalConnNetId === targetTrace.globalConnNetId
|
|
14553
|
-
);
|
|
14554
|
-
if (pathEntersAnyNetLabel({
|
|
14555
|
-
path: tracePath,
|
|
14556
|
-
netLabelPlacements: sameNetLabelPlacements
|
|
14557
|
-
})) {
|
|
14558
|
-
return null;
|
|
14559
|
-
}
|
|
14560
|
-
return candidateNetLabelPlacements;
|
|
14561
|
-
};
|
|
14562
|
-
var candidateIsBetter = (candidate, bestCandidate) => {
|
|
14563
|
-
if (!bestCandidate) return true;
|
|
14564
|
-
const visibleLengthDelta = candidate.netVisibleLength - bestCandidate.netVisibleLength;
|
|
14565
|
-
if (Math.abs(visibleLengthDelta) > TRACE_LENGTH_EPSILON) {
|
|
14566
|
-
return visibleLengthDelta < 0;
|
|
14567
|
-
}
|
|
14568
|
-
return candidate.netVisibleSegmentCount < bestCandidate.netVisibleSegmentCount;
|
|
14569
|
-
};
|
|
14570
|
-
var getBestCycleCollapseCandidate = ({
|
|
14571
|
-
targetTrace,
|
|
14572
|
-
traces,
|
|
14573
|
-
netLabelPlacements
|
|
14574
|
-
}) => {
|
|
14575
|
-
const sameNetTraces = traces.filter(
|
|
14576
|
-
(trace) => trace.globalConnNetId === targetTrace.globalConnNetId
|
|
14577
|
-
);
|
|
14578
|
-
const baselineNetVisibleLength = getVisibleTraceLength(sameNetTraces);
|
|
14579
|
-
const baselineTargetVisibleLength = getVisibleTraceLength([targetTrace]);
|
|
14580
|
-
let bestCandidate = null;
|
|
14581
|
-
for (const donorTrace of sameNetTraces) {
|
|
14582
|
-
if (donorTrace.mspPairId === targetTrace.mspPairId) continue;
|
|
14583
|
-
const sharedPin = getSharedPin({
|
|
14584
|
-
donorTrace,
|
|
14585
|
-
branchTrace: targetTrace
|
|
14586
|
-
});
|
|
14587
|
-
if (!sharedPin) continue;
|
|
14588
|
-
const targetPath = getTracePathStartingAtPin(targetTrace, sharedPin);
|
|
14589
|
-
const donorPath = getTracePathStartingAtPin(donorTrace, sharedPin);
|
|
14590
|
-
if (!targetPath || !donorPath) continue;
|
|
14591
|
-
const crossings = getPerpendicularPathCrossings(targetPath, donorPath);
|
|
14592
|
-
for (const crossing of crossings) {
|
|
14593
|
-
const tracePath = buildCollapsedCyclePath({
|
|
14594
|
-
targetTrace,
|
|
14595
|
-
targetPath,
|
|
14596
|
-
donorPath,
|
|
14597
|
-
crossing
|
|
14598
|
-
});
|
|
14599
|
-
const candidateTrace = { ...targetTrace, tracePath };
|
|
14600
|
-
const candidateTargetVisibleLength = getVisibleTraceLength([
|
|
14601
|
-
candidateTrace
|
|
14602
|
-
]);
|
|
14603
|
-
if (candidateTargetVisibleLength > baselineTargetVisibleLength + TRACE_LENGTH_EPSILON) {
|
|
14604
|
-
continue;
|
|
14605
|
-
}
|
|
14606
|
-
const candidateNetLabelPlacements = getNetLabelPlacementsForCycleCollapse(
|
|
14607
|
-
{
|
|
14608
|
-
targetTrace,
|
|
14609
|
-
tracePath,
|
|
14610
|
-
netLabelPlacements
|
|
14611
|
-
}
|
|
14612
|
-
);
|
|
14613
|
-
if (!candidateNetLabelPlacements) continue;
|
|
14614
|
-
const candidateNetTraces = sameNetTraces.map((trace) => {
|
|
14615
|
-
if (trace.mspPairId === targetTrace.mspPairId) return candidateTrace;
|
|
14616
|
-
return trace;
|
|
14617
|
-
});
|
|
14618
|
-
const netVisibleLength = getVisibleTraceLength(candidateNetTraces);
|
|
14619
|
-
if (netVisibleLength >= baselineNetVisibleLength - TRACE_LENGTH_EPSILON) {
|
|
14620
|
-
continue;
|
|
14621
|
-
}
|
|
14622
|
-
const netVisibleSegmentCount = getVisibleTraceSegmentCount(candidateNetTraces);
|
|
14623
|
-
const candidate = {
|
|
14624
|
-
tracePath,
|
|
14625
|
-
netLabelPlacements: candidateNetLabelPlacements,
|
|
14626
|
-
netVisibleLength,
|
|
14627
|
-
netVisibleSegmentCount
|
|
14628
|
-
};
|
|
14629
|
-
if (candidateIsBetter(candidate, bestCandidate)) {
|
|
14630
|
-
bestCandidate = candidate;
|
|
14631
|
-
}
|
|
14632
|
-
}
|
|
14633
|
-
}
|
|
14634
|
-
return bestCandidate;
|
|
14635
|
-
};
|
|
14636
|
-
var collapseSameNetCycles = ({
|
|
14637
|
-
traces,
|
|
14638
|
-
netLabelPlacements
|
|
14639
|
-
}) => {
|
|
14640
|
-
const outputTraces = [...traces];
|
|
14641
|
-
let outputNetLabelPlacements = [...netLabelPlacements];
|
|
14642
|
-
let collapsedCycleCount = 0;
|
|
14643
|
-
let traceIndex = 0;
|
|
14644
|
-
while (traceIndex < outputTraces.length) {
|
|
14645
|
-
const targetTrace = outputTraces[traceIndex];
|
|
14646
|
-
const candidate = getBestCycleCollapseCandidate({
|
|
14647
|
-
targetTrace,
|
|
14648
|
-
traces: outputTraces,
|
|
14649
|
-
netLabelPlacements: outputNetLabelPlacements
|
|
14650
|
-
});
|
|
14651
|
-
if (!candidate) {
|
|
14652
|
-
traceIndex++;
|
|
14653
|
-
continue;
|
|
14654
|
-
}
|
|
14655
|
-
outputTraces[traceIndex] = {
|
|
14656
|
-
...targetTrace,
|
|
14657
|
-
tracePath: candidate.tracePath
|
|
14658
|
-
};
|
|
14659
|
-
outputNetLabelPlacements = candidate.netLabelPlacements;
|
|
14660
|
-
collapsedCycleCount++;
|
|
14661
|
-
traceIndex = 0;
|
|
14662
|
-
}
|
|
14694
|
+
outputNetLabelPlacements = cycleCollapse.netLabelPlacements;
|
|
14663
14695
|
return {
|
|
14664
14696
|
traces: outputTraces,
|
|
14665
14697
|
netLabelPlacements: outputNetLabelPlacements,
|
|
14666
|
-
|
|
14698
|
+
alignedJunctionCount,
|
|
14699
|
+
collapsedCycleCount: cycleCollapse.collapsedCycleCount
|
|
14667
14700
|
};
|
|
14668
14701
|
};
|
|
14669
14702
|
|
|
@@ -14776,18 +14809,14 @@ var SameNetJunctionAlignmentSolver = class extends BaseSolver {
|
|
|
14776
14809
|
}
|
|
14777
14810
|
_step() {
|
|
14778
14811
|
const alignment = alignSameNetJunctions(this.input);
|
|
14779
|
-
|
|
14780
|
-
traces: alignment.traces,
|
|
14781
|
-
netLabelPlacements: alignment.netLabelPlacements
|
|
14782
|
-
});
|
|
14783
|
-
this.outputTraces = cycleCollapse.traces;
|
|
14812
|
+
this.outputTraces = alignment.traces;
|
|
14784
14813
|
this.outputNetLabelPlacements = placeGroundRailLabelsAtOuterEnd({
|
|
14785
14814
|
inputProblem: this.input.inputProblem,
|
|
14786
|
-
traces:
|
|
14787
|
-
netLabelPlacements:
|
|
14815
|
+
traces: alignment.traces,
|
|
14816
|
+
netLabelPlacements: alignment.netLabelPlacements
|
|
14788
14817
|
});
|
|
14789
14818
|
this.stats.alignedJunctionCount = alignment.alignedJunctionCount;
|
|
14790
|
-
this.stats.collapsedCycleCount =
|
|
14819
|
+
this.stats.collapsedCycleCount = alignment.collapsedCycleCount;
|
|
14791
14820
|
this.solved = true;
|
|
14792
14821
|
}
|
|
14793
14822
|
getOutput() {
|
|
@@ -7,7 +7,6 @@ import { visualizeInputProblem } from "lib/solvers/SchematicTracePipelineSolver/
|
|
|
7
7
|
import type { InputProblem } from "lib/types/InputProblem"
|
|
8
8
|
import { getColorFromString } from "lib/utils/getColorFromString"
|
|
9
9
|
import { alignSameNetJunctions } from "./alignSameNetJunctions"
|
|
10
|
-
import { collapseSameNetCycles } from "./collapseSameNetCycles"
|
|
11
10
|
import { placeGroundRailLabelsAtOuterEnd } from "./placeGroundRailLabelsAtOuterEnd"
|
|
12
11
|
|
|
13
12
|
interface SameNetJunctionAlignmentSolverInput {
|
|
@@ -32,18 +31,14 @@ export class SameNetJunctionAlignmentSolver extends BaseSolver {
|
|
|
32
31
|
|
|
33
32
|
override _step() {
|
|
34
33
|
const alignment = alignSameNetJunctions(this.input)
|
|
35
|
-
|
|
36
|
-
traces: alignment.traces,
|
|
37
|
-
netLabelPlacements: alignment.netLabelPlacements,
|
|
38
|
-
})
|
|
39
|
-
this.outputTraces = cycleCollapse.traces
|
|
34
|
+
this.outputTraces = alignment.traces
|
|
40
35
|
this.outputNetLabelPlacements = placeGroundRailLabelsAtOuterEnd({
|
|
41
36
|
inputProblem: this.input.inputProblem,
|
|
42
|
-
traces:
|
|
43
|
-
netLabelPlacements:
|
|
37
|
+
traces: alignment.traces,
|
|
38
|
+
netLabelPlacements: alignment.netLabelPlacements,
|
|
44
39
|
})
|
|
45
40
|
this.stats.alignedJunctionCount = alignment.alignedJunctionCount
|
|
46
|
-
this.stats.collapsedCycleCount =
|
|
41
|
+
this.stats.collapsedCycleCount = alignment.collapsedCycleCount
|
|
47
42
|
this.solved = true
|
|
48
43
|
}
|
|
49
44
|
|
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
isCoordinateOnPinFacingSide,
|
|
35
35
|
} from "./findNearestSharedPinExitRail"
|
|
36
36
|
import { collapseRedundantSharedEndpointStubs } from "./collapseRedundantSharedEndpointStubs"
|
|
37
|
+
import { collapseSameNetCycles } from "./collapseSameNetCycles"
|
|
37
38
|
import { getSharedPin } from "./getSharedPin"
|
|
38
39
|
|
|
39
40
|
interface AlignSameNetJunctionsInput {
|
|
@@ -1314,17 +1315,24 @@ export const alignSameNetJunctions = ({
|
|
|
1314
1315
|
}
|
|
1315
1316
|
}
|
|
1316
1317
|
|
|
1317
|
-
|
|
1318
|
+
// Shared-stub collapse can remove the common pin from one trace path, so
|
|
1319
|
+
// collapse cycles while both paths still expose their shared endpoint.
|
|
1320
|
+
const cycleCollapse = collapseSameNetCycles({
|
|
1318
1321
|
traces: outputTraces,
|
|
1319
1322
|
netLabelPlacements: outputNetLabelPlacements,
|
|
1323
|
+
})
|
|
1324
|
+
outputTraces = collapseRedundantSharedEndpointStubs({
|
|
1325
|
+
traces: cycleCollapse.traces,
|
|
1326
|
+
netLabelPlacements: cycleCollapse.netLabelPlacements,
|
|
1320
1327
|
netLabelConnectorTraceIds,
|
|
1321
1328
|
multiPinNetPinIds: getMultiPinNetPinIds(inputProblem),
|
|
1322
1329
|
})
|
|
1323
|
-
|
|
1330
|
+
outputNetLabelPlacements = cycleCollapse.netLabelPlacements
|
|
1324
1331
|
|
|
1325
1332
|
return {
|
|
1326
1333
|
traces: outputTraces,
|
|
1327
1334
|
netLabelPlacements: outputNetLabelPlacements,
|
|
1328
1335
|
alignedJunctionCount,
|
|
1336
|
+
collapsedCycleCount: cycleCollapse.collapsedCycleCount,
|
|
1329
1337
|
}
|
|
1330
1338
|
}
|