@tscircuit/schematic-trace-solver 0.0.46 → 0.0.47
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 +18 -16
- package/dist/index.js +208 -116
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/TraceLabelOverlapAvoidanceSolver.ts +89 -61
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/rerouteCollidingTrace.ts +16 -5
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/OverlapAvoidanceStepSolver/OverlapAvoidanceStepSolver.ts +27 -16
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/OverlapAvoidanceStepSolver/doesTraceStartOrEndInLabel.ts +58 -0
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/SingleOverlapSolver/SingleOverlapSolver.ts +13 -1
- package/lib/solvers/TraceLabelOverlapAvoidanceSolver/tryFourPointDetour.ts +110 -60
- package/package.json +1 -1
- package/site/examples/example27.page.tsx +4 -0
- package/tests/assets/example27.json +168 -0
- package/tests/examples/__snapshots__/example03.snap.svg +67 -67
- package/tests/examples/__snapshots__/example16.snap.svg +3 -3
- package/tests/examples/__snapshots__/example30.snap.svg +258 -0
- package/tests/examples/example30.test.ts +12 -0
- package/tests/solvers/TraceLabelOverlapAvoidanceSolver/__snapshots__/TraceLabelOverlapAvoidanceSolver.snap.svg +9 -6
package/dist/index.d.ts
CHANGED
|
@@ -435,6 +435,7 @@ declare class SingleOverlapSolver extends BaseSolver {
|
|
|
435
435
|
problem: InputProblem;
|
|
436
436
|
obstacles: ReturnType<typeof getObstacleRects>;
|
|
437
437
|
label: NetLabelPlacement;
|
|
438
|
+
_tried: number;
|
|
438
439
|
constructor(solverInput: SingleOverlapSolverInput);
|
|
439
440
|
_step(): void;
|
|
440
441
|
visualize(): GraphicsObject;
|
|
@@ -446,6 +447,7 @@ interface OverlapCollectionSolverInput {
|
|
|
446
447
|
initialNetLabelPlacements: NetLabelPlacement[];
|
|
447
448
|
mergedNetLabelPlacements: NetLabelPlacement[];
|
|
448
449
|
mergedLabelNetIdMap: Record<string, Set<string>>;
|
|
450
|
+
detourCounts: Map<string, number>;
|
|
449
451
|
}
|
|
450
452
|
/**
|
|
451
453
|
* This is an internal solver that manages the step-by-step process of avoiding
|
|
@@ -458,8 +460,8 @@ declare class OverlapAvoidanceStepSolver extends BaseSolver {
|
|
|
458
460
|
mergedLabelNetIdMap: Record<string, Set<string>>;
|
|
459
461
|
allTraces: SolvedTracePath[];
|
|
460
462
|
modifiedTraces: SolvedTracePath[];
|
|
461
|
-
private detourCountByLabel;
|
|
462
463
|
private readonly PADDING_BUFFER;
|
|
464
|
+
private detourCounts;
|
|
463
465
|
activeSubSolver: SingleOverlapSolver | null;
|
|
464
466
|
private overlapQueue;
|
|
465
467
|
private recentlyFailed;
|
|
@@ -470,6 +472,7 @@ declare class OverlapAvoidanceStepSolver extends BaseSolver {
|
|
|
470
472
|
getOutput(): {
|
|
471
473
|
allTraces: SolvedTracePath[];
|
|
472
474
|
modifiedTraces: SolvedTracePath[];
|
|
475
|
+
detourCounts: Map<string, number>;
|
|
473
476
|
};
|
|
474
477
|
visualize(): GraphicsObject;
|
|
475
478
|
}
|
|
@@ -480,29 +483,28 @@ interface TraceLabelOverlapAvoidanceSolverInput {
|
|
|
480
483
|
netLabelPlacements: NetLabelPlacement[];
|
|
481
484
|
}
|
|
482
485
|
/**
|
|
483
|
-
*
|
|
486
|
+
* Resolves overlaps between schematic traces and net labels using a two-phase,
|
|
487
|
+
* "fire-and-forget" dispatching strategy.
|
|
484
488
|
*
|
|
485
|
-
* This solver
|
|
486
|
-
* 1. **MergedNetLabelObstacleSolver**: This solver first merges labels that are
|
|
487
|
-
* close to each other to form larger "obstacle" groups. This simplifies the
|
|
488
|
-
* problem by reducing the number of individual obstacles the traces need to avoid.
|
|
489
|
-
* 2. **OverlapAvoidanceStepSolver**: This solver then takes the output of the merging
|
|
490
|
-
* step and iteratively attempts to reroute traces to avoid the merged label obstacles.
|
|
491
|
-
* It handles one overlap at a time, making it a step-by-step process.
|
|
489
|
+
* This solver operates in two distinct phases:
|
|
492
490
|
*
|
|
493
|
-
*
|
|
494
|
-
*
|
|
491
|
+
* 1. **Dispatch Phase**: Iterates through traces, identifying clean ones and dispatching
|
|
492
|
+
* colliding ones to dedicated `OverlapAvoidanceStepSolver` instances.
|
|
495
493
|
*
|
|
496
|
-
*
|
|
497
|
-
*
|
|
494
|
+
* 2. **Execution Phase**: Steps through all dispatched sub-solvers until they complete.
|
|
495
|
+
*
|
|
496
|
+
* The final output combines clean traces with results from sub-solvers. A final
|
|
497
|
+
* `MergedNetLabelObstacleSolver` ensures pipeline compatibility.
|
|
498
498
|
*/
|
|
499
499
|
declare class TraceLabelOverlapAvoidanceSolver extends BaseSolver {
|
|
500
500
|
inputProblem: InputProblem;
|
|
501
|
-
traces: SolvedTracePath[];
|
|
502
501
|
netLabelPlacements: NetLabelPlacement[];
|
|
502
|
+
unprocessedTraces: SolvedTracePath[];
|
|
503
|
+
cleanTraces: SolvedTracePath[];
|
|
504
|
+
subSolvers: OverlapAvoidanceStepSolver[];
|
|
505
|
+
private phase;
|
|
506
|
+
detourCounts: Map<string, number>;
|
|
503
507
|
labelMergingSolver?: MergedNetLabelObstacleSolver;
|
|
504
|
-
overlapAvoidanceSolver?: OverlapAvoidanceStepSolver;
|
|
505
|
-
pipelineStepIndex: number;
|
|
506
508
|
constructor(solverInput: TraceLabelOverlapAvoidanceSolverInput);
|
|
507
509
|
_step(): void;
|
|
508
510
|
getOutput(): {
|
package/dist/index.js
CHANGED
|
@@ -2649,73 +2649,106 @@ var generateFourPointDetourCandidates = ({
|
|
|
2649
2649
|
paddingBuffer,
|
|
2650
2650
|
detourCount
|
|
2651
2651
|
}) => {
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2652
|
+
const isMergedLabel = label.globalConnNetId.startsWith("merged-group-");
|
|
2653
|
+
const effectivePadding = paddingBuffer + detourCount * paddingBuffer;
|
|
2654
|
+
const paddedLabelBounds = {
|
|
2655
|
+
minX: labelBounds.minX - effectivePadding,
|
|
2656
|
+
maxX: labelBounds.maxX + effectivePadding,
|
|
2657
|
+
minY: labelBounds.minY - effectivePadding,
|
|
2658
|
+
maxY: labelBounds.maxY + effectivePadding
|
|
2659
|
+
};
|
|
2660
|
+
let entryPoint, exitPoint;
|
|
2661
|
+
let entryIndex, exitIndex;
|
|
2662
|
+
const isPointInRect = (p) => p.x >= paddedLabelBounds.minX && p.x <= paddedLabelBounds.maxX && p.y >= paddedLabelBounds.minY && p.y <= paddedLabelBounds.maxY;
|
|
2663
|
+
if (isMergedLabel) {
|
|
2664
|
+
let firstInsideIndex = -1;
|
|
2665
|
+
for (let i = 0; i < initialTrace.tracePath.length; i++) {
|
|
2666
|
+
if (isPointInRect(initialTrace.tracePath[i])) {
|
|
2667
|
+
firstInsideIndex = i;
|
|
2668
|
+
break;
|
|
2669
|
+
}
|
|
2670
|
+
}
|
|
2671
|
+
if (firstInsideIndex === -1) return [];
|
|
2672
|
+
entryIndex = Math.max(0, firstInsideIndex - 1);
|
|
2673
|
+
entryPoint = initialTrace.tracePath[entryIndex];
|
|
2674
|
+
let firstOutsideIndex = -1;
|
|
2675
|
+
for (let i = firstInsideIndex; i < initialTrace.tracePath.length; i++) {
|
|
2676
|
+
if (!isPointInRect(initialTrace.tracePath[i])) {
|
|
2677
|
+
firstOutsideIndex = i;
|
|
2678
|
+
break;
|
|
2679
|
+
}
|
|
2661
2680
|
}
|
|
2681
|
+
if (firstOutsideIndex === -1) {
|
|
2682
|
+
exitIndex = initialTrace.tracePath.length - 1;
|
|
2683
|
+
} else {
|
|
2684
|
+
exitIndex = firstOutsideIndex;
|
|
2685
|
+
}
|
|
2686
|
+
exitPoint = initialTrace.tracePath[exitIndex];
|
|
2687
|
+
} else {
|
|
2688
|
+
let collidingSegIndex = -1;
|
|
2689
|
+
for (let i = 0; i < initialTrace.tracePath.length - 1; i++) {
|
|
2690
|
+
if (segmentIntersectsRect(
|
|
2691
|
+
initialTrace.tracePath[i],
|
|
2692
|
+
initialTrace.tracePath[i + 1],
|
|
2693
|
+
{ ...paddedLabelBounds, chipId: "temp-obstacle" }
|
|
2694
|
+
)) {
|
|
2695
|
+
collidingSegIndex = i;
|
|
2696
|
+
break;
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
if (collidingSegIndex === -1) return [];
|
|
2700
|
+
entryIndex = collidingSegIndex;
|
|
2701
|
+
exitIndex = collidingSegIndex + 1;
|
|
2702
|
+
entryPoint = initialTrace.tracePath[entryIndex];
|
|
2703
|
+
exitPoint = initialTrace.tracePath[exitIndex];
|
|
2662
2704
|
}
|
|
2663
|
-
if (
|
|
2664
|
-
const pA = initialTrace.tracePath[collidingSegIndex];
|
|
2665
|
-
const pB = initialTrace.tracePath[collidingSegIndex + 1];
|
|
2666
|
-
if (!pA || !pB) return [];
|
|
2705
|
+
if (!entryPoint || !exitPoint || entryIndex >= exitIndex) return [];
|
|
2667
2706
|
const candidateDetours = [];
|
|
2668
|
-
const
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
const effectivePadding = paddingBuffer + detourCount * paddingBuffer;
|
|
2674
|
-
if (isVertical(pA, pB)) {
|
|
2675
|
-
const xCandidates = [
|
|
2676
|
-
paddedLabelBounds.maxX + effectivePadding,
|
|
2677
|
-
paddedLabelBounds.minX - effectivePadding
|
|
2678
|
-
];
|
|
2679
|
-
for (const newX of xCandidates) {
|
|
2707
|
+
const dx = exitPoint.x - entryPoint.x;
|
|
2708
|
+
const dy = exitPoint.y - entryPoint.y;
|
|
2709
|
+
if (Math.abs(dx) > Math.abs(dy)) {
|
|
2710
|
+
const yCandidates = [paddedLabelBounds.maxY, paddedLabelBounds.minY];
|
|
2711
|
+
for (const newY of yCandidates) {
|
|
2680
2712
|
candidateDetours.push(
|
|
2681
|
-
|
|
2682
|
-
{ x:
|
|
2683
|
-
{ x:
|
|
2684
|
-
{ x:
|
|
2685
|
-
{ x:
|
|
2713
|
+
dx > 0 ? [
|
|
2714
|
+
{ x: paddedLabelBounds.minX, y: entryPoint.y },
|
|
2715
|
+
{ x: paddedLabelBounds.minX, y: newY },
|
|
2716
|
+
{ x: paddedLabelBounds.maxX, y: newY },
|
|
2717
|
+
{ x: paddedLabelBounds.maxX, y: exitPoint.y }
|
|
2686
2718
|
] : [
|
|
2687
|
-
|
|
2688
|
-
{ x:
|
|
2689
|
-
{ x:
|
|
2690
|
-
{ x:
|
|
2719
|
+
// Right-to-left
|
|
2720
|
+
{ x: paddedLabelBounds.maxX, y: entryPoint.y },
|
|
2721
|
+
{ x: paddedLabelBounds.maxX, y: newY },
|
|
2722
|
+
{ x: paddedLabelBounds.minX, y: newY },
|
|
2723
|
+
{ x: paddedLabelBounds.minX, y: exitPoint.y }
|
|
2691
2724
|
]
|
|
2692
2725
|
);
|
|
2693
2726
|
}
|
|
2694
2727
|
} else {
|
|
2695
|
-
const
|
|
2696
|
-
|
|
2697
|
-
paddedLabelBounds.minY - effectivePadding
|
|
2698
|
-
];
|
|
2699
|
-
for (const newY of yCandidates) {
|
|
2728
|
+
const xCandidates = [paddedLabelBounds.maxX, paddedLabelBounds.minX];
|
|
2729
|
+
for (const newX of xCandidates) {
|
|
2700
2730
|
candidateDetours.push(
|
|
2701
|
-
|
|
2702
|
-
{ x:
|
|
2703
|
-
{ x:
|
|
2704
|
-
{ x:
|
|
2705
|
-
{ x:
|
|
2731
|
+
dy > 0 ? [
|
|
2732
|
+
{ x: entryPoint.x, y: paddedLabelBounds.minY },
|
|
2733
|
+
{ x: newX, y: paddedLabelBounds.minY },
|
|
2734
|
+
{ x: newX, y: paddedLabelBounds.maxY },
|
|
2735
|
+
{ x: exitPoint.x, y: paddedLabelBounds.maxY }
|
|
2706
2736
|
] : [
|
|
2707
|
-
|
|
2708
|
-
{ x:
|
|
2709
|
-
{ x:
|
|
2710
|
-
{ x:
|
|
2737
|
+
// Bottom-to-top
|
|
2738
|
+
{ x: entryPoint.x, y: paddedLabelBounds.maxY },
|
|
2739
|
+
{ x: newX, y: paddedLabelBounds.maxY },
|
|
2740
|
+
{ x: newX, y: paddedLabelBounds.minY },
|
|
2741
|
+
{ x: exitPoint.x, y: paddedLabelBounds.minY }
|
|
2711
2742
|
]
|
|
2712
2743
|
);
|
|
2713
2744
|
}
|
|
2714
2745
|
}
|
|
2715
2746
|
return candidateDetours.map((detourPoints) => [
|
|
2716
|
-
...initialTrace.tracePath.slice(0,
|
|
2747
|
+
...initialTrace.tracePath.slice(0, entryIndex),
|
|
2748
|
+
entryPoint,
|
|
2717
2749
|
...detourPoints,
|
|
2718
|
-
|
|
2750
|
+
exitPoint,
|
|
2751
|
+
...initialTrace.tracePath.slice(exitIndex + 1)
|
|
2719
2752
|
]);
|
|
2720
2753
|
};
|
|
2721
2754
|
|
|
@@ -2759,13 +2792,12 @@ var generateRerouteCandidates = ({
|
|
|
2759
2792
|
if (trace.globalConnNetId === label.globalConnNetId) {
|
|
2760
2793
|
return [initialTrace.tracePath];
|
|
2761
2794
|
}
|
|
2762
|
-
const labelPadding = paddingBuffer;
|
|
2763
2795
|
const labelBoundsRaw = getRectBounds(label.center, label.width, label.height);
|
|
2764
2796
|
const labelBounds = {
|
|
2765
|
-
minX: labelBoundsRaw.minX
|
|
2766
|
-
minY: labelBoundsRaw.minY
|
|
2767
|
-
maxX: labelBoundsRaw.maxX
|
|
2768
|
-
maxY: labelBoundsRaw.maxY
|
|
2797
|
+
minX: labelBoundsRaw.minX,
|
|
2798
|
+
minY: labelBoundsRaw.minY,
|
|
2799
|
+
maxX: labelBoundsRaw.maxX,
|
|
2800
|
+
maxY: labelBoundsRaw.maxY,
|
|
2769
2801
|
chipId: `netlabel-${label.netId}`
|
|
2770
2802
|
};
|
|
2771
2803
|
const fourPointCandidates = generateFourPointDetourCandidates({
|
|
@@ -2791,6 +2823,7 @@ var generateRerouteCandidates = ({
|
|
|
2791
2823
|
};
|
|
2792
2824
|
|
|
2793
2825
|
// lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/SingleOverlapSolver/SingleOverlapSolver.ts
|
|
2826
|
+
var MAX_TRIES = 5;
|
|
2794
2827
|
var SingleOverlapSolver = class extends BaseSolver {
|
|
2795
2828
|
queuedCandidatePaths;
|
|
2796
2829
|
solvedTracePath = null;
|
|
@@ -2798,13 +2831,17 @@ var SingleOverlapSolver = class extends BaseSolver {
|
|
|
2798
2831
|
problem;
|
|
2799
2832
|
obstacles;
|
|
2800
2833
|
label;
|
|
2834
|
+
_tried = 0;
|
|
2801
2835
|
constructor(solverInput) {
|
|
2802
2836
|
super();
|
|
2803
2837
|
this.initialTrace = solverInput.trace;
|
|
2804
2838
|
this.problem = solverInput.problem;
|
|
2805
2839
|
this.label = solverInput.label;
|
|
2840
|
+
const effectivePadding = solverInput.paddingBuffer + solverInput.detourCount * solverInput.paddingBuffer;
|
|
2806
2841
|
const candidates = generateRerouteCandidates({
|
|
2807
|
-
...solverInput
|
|
2842
|
+
...solverInput,
|
|
2843
|
+
paddingBuffer: effectivePadding
|
|
2844
|
+
// Use the calculated, larger padding
|
|
2808
2845
|
});
|
|
2809
2846
|
const getPathLength = (pts) => {
|
|
2810
2847
|
let len = 0;
|
|
@@ -2821,10 +2858,11 @@ var SingleOverlapSolver = class extends BaseSolver {
|
|
|
2821
2858
|
this.obstacles = getObstacleRects(this.problem);
|
|
2822
2859
|
}
|
|
2823
2860
|
_step() {
|
|
2824
|
-
if (this.queuedCandidatePaths.length === 0) {
|
|
2861
|
+
if (this.queuedCandidatePaths.length === 0 || this._tried >= MAX_TRIES) {
|
|
2825
2862
|
this.failed = true;
|
|
2826
2863
|
return;
|
|
2827
2864
|
}
|
|
2865
|
+
this._tried++;
|
|
2828
2866
|
const nextCandidatePath = this.queuedCandidatePaths.shift();
|
|
2829
2867
|
const simplifiedPath = simplifyPath(nextCandidatePath);
|
|
2830
2868
|
if (!isPathCollidingWithObstacles(simplifiedPath, this.obstacles)) {
|
|
@@ -2866,13 +2904,38 @@ var SingleOverlapSolver = class extends BaseSolver {
|
|
|
2866
2904
|
}
|
|
2867
2905
|
};
|
|
2868
2906
|
|
|
2869
|
-
// lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/OverlapAvoidanceStepSolver/
|
|
2870
|
-
var
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
}
|
|
2874
|
-
const
|
|
2875
|
-
|
|
2907
|
+
// lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/OverlapAvoidanceStepSolver/doesTraceStartOrEndInLabel.ts
|
|
2908
|
+
var doesTraceStartOrEndInLabel = ({ trace, label }) => {
|
|
2909
|
+
if (trace.tracePath.length < 2) {
|
|
2910
|
+
return false;
|
|
2911
|
+
}
|
|
2912
|
+
const firstSegmentTrace = {
|
|
2913
|
+
...trace,
|
|
2914
|
+
tracePath: [trace.tracePath[0], trace.tracePath[1]]
|
|
2915
|
+
};
|
|
2916
|
+
const firstSegmentOverlap = detectTraceLabelOverlap({
|
|
2917
|
+
traces: [firstSegmentTrace],
|
|
2918
|
+
netLabels: [label]
|
|
2919
|
+
});
|
|
2920
|
+
if (firstSegmentOverlap.length > 0) {
|
|
2921
|
+
return true;
|
|
2922
|
+
}
|
|
2923
|
+
if (trace.tracePath.length > 2) {
|
|
2924
|
+
const lastPoint = trace.tracePath[trace.tracePath.length - 1];
|
|
2925
|
+
const secondToLastPoint = trace.tracePath[trace.tracePath.length - 2];
|
|
2926
|
+
const lastSegmentTrace = {
|
|
2927
|
+
...trace,
|
|
2928
|
+
tracePath: [secondToLastPoint, lastPoint]
|
|
2929
|
+
};
|
|
2930
|
+
const lastSegmentOverlap = detectTraceLabelOverlap({
|
|
2931
|
+
traces: [lastSegmentTrace],
|
|
2932
|
+
netLabels: [label]
|
|
2933
|
+
});
|
|
2934
|
+
if (lastSegmentOverlap.length > 0) {
|
|
2935
|
+
return true;
|
|
2936
|
+
}
|
|
2937
|
+
}
|
|
2938
|
+
return false;
|
|
2876
2939
|
};
|
|
2877
2940
|
|
|
2878
2941
|
// lib/solvers/TraceLabelOverlapAvoidanceSolver/sub-solvers/OverlapAvoidanceStepSolver/visualizeDecomposition.ts
|
|
@@ -2908,8 +2971,8 @@ var OverlapAvoidanceStepSolver = class extends BaseSolver {
|
|
|
2908
2971
|
mergedLabelNetIdMap;
|
|
2909
2972
|
allTraces;
|
|
2910
2973
|
modifiedTraces = [];
|
|
2911
|
-
detourCountByLabel = {};
|
|
2912
2974
|
PADDING_BUFFER = 0.1;
|
|
2975
|
+
detourCounts = /* @__PURE__ */ new Map();
|
|
2913
2976
|
activeSubSolver = null;
|
|
2914
2977
|
overlapQueue = [];
|
|
2915
2978
|
recentlyFailed = /* @__PURE__ */ new Set();
|
|
@@ -2922,6 +2985,7 @@ var OverlapAvoidanceStepSolver = class extends BaseSolver {
|
|
|
2922
2985
|
this.mergedNetLabelPlacements = solverInput.mergedNetLabelPlacements;
|
|
2923
2986
|
this.mergedLabelNetIdMap = solverInput.mergedLabelNetIdMap;
|
|
2924
2987
|
this.allTraces = [...solverInput.traces];
|
|
2988
|
+
this.detourCounts = solverInput.detourCounts;
|
|
2925
2989
|
}
|
|
2926
2990
|
_step() {
|
|
2927
2991
|
this.currentlyProcessingOverlap = null;
|
|
@@ -2973,7 +3037,6 @@ var OverlapAvoidanceStepSolver = class extends BaseSolver {
|
|
|
2973
3037
|
(t) => t.mspPairId === nextOverlap.trace.mspPairId
|
|
2974
3038
|
);
|
|
2975
3039
|
const labelToAvoid = nextOverlap.label;
|
|
2976
|
-
const traceStartPoint = traceToFix.tracePath[0];
|
|
2977
3040
|
const originalNetIds = this.mergedLabelNetIdMap[labelToAvoid.globalConnNetId];
|
|
2978
3041
|
const isSelfOverlap = originalNetIds?.has(traceToFix.globalConnNetId);
|
|
2979
3042
|
if (isSelfOverlap) {
|
|
@@ -2993,9 +3056,11 @@ var OverlapAvoidanceStepSolver = class extends BaseSolver {
|
|
|
2993
3056
|
}
|
|
2994
3057
|
}
|
|
2995
3058
|
if (actualOverlapLabel) {
|
|
2996
|
-
const
|
|
2997
|
-
|
|
2998
|
-
|
|
3059
|
+
const detourCount2 = this.detourCounts.get(actualOverlapLabel.globalConnNetId) ?? 0;
|
|
3060
|
+
this.detourCounts.set(
|
|
3061
|
+
actualOverlapLabel.globalConnNetId,
|
|
3062
|
+
detourCount2 + 1
|
|
3063
|
+
);
|
|
2999
3064
|
this.activeSubSolver = new SingleOverlapSolver({
|
|
3000
3065
|
trace: traceToFix,
|
|
3001
3066
|
label: actualOverlapLabel,
|
|
@@ -3009,7 +3074,7 @@ var OverlapAvoidanceStepSolver = class extends BaseSolver {
|
|
|
3009
3074
|
}
|
|
3010
3075
|
return;
|
|
3011
3076
|
}
|
|
3012
|
-
if (originalNetIds &&
|
|
3077
|
+
if (originalNetIds && doesTraceStartOrEndInLabel({ trace: traceToFix, label: labelToAvoid })) {
|
|
3013
3078
|
const childLabels = this.initialNetLabelPlacements.filter(
|
|
3014
3079
|
(l) => originalNetIds.has(l.globalConnNetId)
|
|
3015
3080
|
);
|
|
@@ -3026,9 +3091,11 @@ var OverlapAvoidanceStepSolver = class extends BaseSolver {
|
|
|
3026
3091
|
}
|
|
3027
3092
|
}
|
|
3028
3093
|
if (actualOverlapLabel) {
|
|
3029
|
-
const
|
|
3030
|
-
|
|
3031
|
-
|
|
3094
|
+
const detourCount2 = this.detourCounts.get(actualOverlapLabel.globalConnNetId) ?? 0;
|
|
3095
|
+
this.detourCounts.set(
|
|
3096
|
+
actualOverlapLabel.globalConnNetId,
|
|
3097
|
+
detourCount2 + 1
|
|
3098
|
+
);
|
|
3032
3099
|
this.activeSubSolver = new SingleOverlapSolver({
|
|
3033
3100
|
trace: traceToFix,
|
|
3034
3101
|
label: actualOverlapLabel,
|
|
@@ -3042,9 +3109,8 @@ var OverlapAvoidanceStepSolver = class extends BaseSolver {
|
|
|
3042
3109
|
}
|
|
3043
3110
|
return;
|
|
3044
3111
|
}
|
|
3045
|
-
const
|
|
3046
|
-
|
|
3047
|
-
this.detourCountByLabel[labelId] = detourCount + 1;
|
|
3112
|
+
const detourCount = this.detourCounts.get(labelToAvoid.globalConnNetId) ?? 0;
|
|
3113
|
+
this.detourCounts.set(labelToAvoid.globalConnNetId, detourCount + 1);
|
|
3048
3114
|
this.activeSubSolver = new SingleOverlapSolver({
|
|
3049
3115
|
trace: traceToFix,
|
|
3050
3116
|
label: labelToAvoid,
|
|
@@ -3057,7 +3123,8 @@ var OverlapAvoidanceStepSolver = class extends BaseSolver {
|
|
|
3057
3123
|
getOutput() {
|
|
3058
3124
|
return {
|
|
3059
3125
|
allTraces: this.allTraces,
|
|
3060
|
-
modifiedTraces: this.modifiedTraces
|
|
3126
|
+
modifiedTraces: this.modifiedTraces,
|
|
3127
|
+
detourCounts: this.detourCounts
|
|
3061
3128
|
};
|
|
3062
3129
|
}
|
|
3063
3130
|
visualize() {
|
|
@@ -3110,76 +3177,101 @@ var OverlapAvoidanceStepSolver = class extends BaseSolver {
|
|
|
3110
3177
|
// lib/solvers/TraceLabelOverlapAvoidanceSolver/TraceLabelOverlapAvoidanceSolver.ts
|
|
3111
3178
|
var TraceLabelOverlapAvoidanceSolver = class extends BaseSolver {
|
|
3112
3179
|
inputProblem;
|
|
3113
|
-
traces;
|
|
3114
3180
|
netLabelPlacements;
|
|
3115
|
-
|
|
3181
|
+
unprocessedTraces = [];
|
|
3182
|
+
cleanTraces = [];
|
|
3183
|
+
subSolvers = [];
|
|
3184
|
+
phase = "searching_for_overlaps";
|
|
3185
|
+
detourCounts = /* @__PURE__ */ new Map();
|
|
3116
3186
|
labelMergingSolver;
|
|
3117
|
-
overlapAvoidanceSolver;
|
|
3118
|
-
pipelineStepIndex = 0;
|
|
3119
3187
|
constructor(solverInput) {
|
|
3120
3188
|
super();
|
|
3121
3189
|
this.inputProblem = solverInput.inputProblem;
|
|
3122
|
-
this.
|
|
3190
|
+
this.unprocessedTraces = [...solverInput.traces];
|
|
3123
3191
|
this.netLabelPlacements = solverInput.netLabelPlacements;
|
|
3192
|
+
this.cleanTraces = [];
|
|
3193
|
+
this.subSolvers = [];
|
|
3124
3194
|
}
|
|
3125
3195
|
_step() {
|
|
3126
|
-
if (this.
|
|
3127
|
-
this.
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
this.activeSubSolver = null;
|
|
3196
|
+
if (this.phase === "searching_for_overlaps") {
|
|
3197
|
+
if (this.unprocessedTraces.length === 0) {
|
|
3198
|
+
console.log(
|
|
3199
|
+
`Dispatch phase complete. Created ${this.subSolvers.length} sub-solvers.`
|
|
3200
|
+
);
|
|
3201
|
+
this.phase = "fixing_overlaps";
|
|
3202
|
+
return;
|
|
3134
3203
|
}
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3204
|
+
const currentTargetTrace = this.unprocessedTraces.shift();
|
|
3205
|
+
const localOverlaps = detectTraceLabelOverlap({
|
|
3206
|
+
traces: [currentTargetTrace],
|
|
3207
|
+
netLabels: this.netLabelPlacements
|
|
3208
|
+
});
|
|
3209
|
+
if (localOverlaps.length === 0) {
|
|
3210
|
+
this.cleanTraces.push(currentTargetTrace);
|
|
3211
|
+
} else {
|
|
3212
|
+
const collidingLabels = localOverlaps.map((o) => o.label);
|
|
3213
|
+
const labelMerger = new MergedNetLabelObstacleSolver({
|
|
3214
|
+
netLabelPlacements: collidingLabels,
|
|
3141
3215
|
inputProblem: this.inputProblem,
|
|
3142
|
-
traces:
|
|
3216
|
+
traces: [currentTargetTrace]
|
|
3143
3217
|
});
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
this.overlapAvoidanceSolver = new OverlapAvoidanceStepSolver({
|
|
3218
|
+
labelMerger.solve();
|
|
3219
|
+
const mergingOutput = labelMerger.getOutput();
|
|
3220
|
+
const subSolver = new OverlapAvoidanceStepSolver({
|
|
3148
3221
|
inputProblem: this.inputProblem,
|
|
3149
|
-
traces:
|
|
3222
|
+
traces: [currentTargetTrace],
|
|
3150
3223
|
initialNetLabelPlacements: this.netLabelPlacements,
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3224
|
+
mergedNetLabelPlacements: mergingOutput.netLabelPlacements,
|
|
3225
|
+
mergedLabelNetIdMap: mergingOutput.mergedLabelNetIdMap,
|
|
3226
|
+
detourCounts: this.detourCounts
|
|
3154
3227
|
});
|
|
3155
|
-
this.
|
|
3156
|
-
|
|
3157
|
-
|
|
3228
|
+
this.subSolvers.push(subSolver);
|
|
3229
|
+
}
|
|
3230
|
+
} else if (this.phase === "fixing_overlaps") {
|
|
3231
|
+
if (this.subSolvers.every((s) => s.solved || s.failed)) {
|
|
3232
|
+
console.log("All sub-solvers finished.");
|
|
3233
|
+
if (!this.labelMergingSolver) {
|
|
3234
|
+
this.labelMergingSolver = new MergedNetLabelObstacleSolver({
|
|
3235
|
+
netLabelPlacements: this.netLabelPlacements,
|
|
3236
|
+
inputProblem: this.inputProblem,
|
|
3237
|
+
traces: this.getOutput().traces
|
|
3238
|
+
});
|
|
3239
|
+
this.labelMergingSolver.solve();
|
|
3240
|
+
}
|
|
3158
3241
|
this.solved = true;
|
|
3159
|
-
|
|
3242
|
+
return;
|
|
3243
|
+
}
|
|
3244
|
+
for (const solver of this.subSolvers) {
|
|
3245
|
+
if (!solver.solved && !solver.failed) {
|
|
3246
|
+
solver.step();
|
|
3247
|
+
}
|
|
3248
|
+
}
|
|
3160
3249
|
}
|
|
3161
3250
|
}
|
|
3162
3251
|
getOutput() {
|
|
3252
|
+
const solvedTraces = this.subSolvers.flatMap((s) => s.getOutput().allTraces);
|
|
3163
3253
|
return {
|
|
3164
|
-
traces: this.
|
|
3254
|
+
traces: [...this.cleanTraces, ...solvedTraces],
|
|
3165
3255
|
netLabelPlacements: this.labelMergingSolver?.getOutput().netLabelPlacements ?? this.netLabelPlacements
|
|
3166
3256
|
};
|
|
3167
3257
|
}
|
|
3168
3258
|
visualize() {
|
|
3169
|
-
if (this.activeSubSolver) {
|
|
3170
|
-
return this.activeSubSolver.visualize();
|
|
3171
|
-
}
|
|
3172
3259
|
const graphics = visualizeInputProblem(this.inputProblem);
|
|
3173
3260
|
if (!graphics.lines) graphics.lines = [];
|
|
3174
3261
|
if (!graphics.rects) graphics.rects = [];
|
|
3175
|
-
const
|
|
3176
|
-
for (const trace of output.traces) {
|
|
3262
|
+
for (const trace of this.cleanTraces) {
|
|
3177
3263
|
graphics.lines.push({
|
|
3178
3264
|
points: trace.tracePath,
|
|
3179
3265
|
strokeColor: "purple"
|
|
3180
3266
|
});
|
|
3181
3267
|
}
|
|
3182
|
-
for (const
|
|
3268
|
+
for (const solver of this.subSolvers) {
|
|
3269
|
+
const solverGraphics = solver.visualize();
|
|
3270
|
+
graphics.lines.push(...solverGraphics.lines ?? []);
|
|
3271
|
+
graphics.rects.push(...solverGraphics.rects ?? []);
|
|
3272
|
+
graphics.points.push(...solverGraphics.points ?? []);
|
|
3273
|
+
}
|
|
3274
|
+
for (const label of this.netLabelPlacements) {
|
|
3183
3275
|
const color = getColorFromString(label.globalConnNetId, 0.3);
|
|
3184
3276
|
graphics.rects.push({
|
|
3185
3277
|
center: label.center,
|