@tscircuit/schematic-trace-solver 0.0.82 → 0.0.83
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/biome.json +5 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +164 -73
- package/lib/solvers/Example28Solver/Example28Solver.ts +114 -2
- package/lib/solvers/Example28Solver/reroute.ts +32 -21
- package/package.json +1 -1
- package/tests/examples/__snapshots__/example03.snap.svg +64 -64
- package/tests/examples/__snapshots__/example28.snap.svg +21 -18
- package/tests/examples/__snapshots__/example32.snap.svg +3 -3
- package/tests/examples/__snapshots__/example48.snap.svg +30 -30
- package/tests/repros/__snapshots__/repro51-overlap-junction-crossing.snap.svg +177 -0
- package/tests/repros/assets/repro51-overlap-junction-crossing.input.json +129 -0
- package/tests/repros/repro51-overlap-junction-crossing.test.ts +105 -0
package/biome.json
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -666,6 +666,7 @@ declare class Example28Solver extends BaseSolver {
|
|
|
666
666
|
currentOverlap: TraceLabelOverlap | null;
|
|
667
667
|
currentCandidateResults: RerouteCandidateResult[];
|
|
668
668
|
private chipObstacles;
|
|
669
|
+
private pinMap;
|
|
669
670
|
constructor(params: Example28SolverParams);
|
|
670
671
|
getConstructorParams(): ConstructorParameters<typeof Example28Solver>[0];
|
|
671
672
|
_step(): void;
|
|
@@ -679,6 +680,7 @@ declare class Example28Solver extends BaseSolver {
|
|
|
679
680
|
private isOverlapStillPresent;
|
|
680
681
|
private getCurrentTrace;
|
|
681
682
|
private rerouteOverlappingTrace;
|
|
683
|
+
private tryMoveLabelOutward;
|
|
682
684
|
visualize(): GraphicsObject;
|
|
683
685
|
}
|
|
684
686
|
|
package/dist/index.js
CHANGED
|
@@ -5162,6 +5162,54 @@ var TraceCleanupSolver = class extends BaseSolver {
|
|
|
5162
5162
|
}
|
|
5163
5163
|
};
|
|
5164
5164
|
|
|
5165
|
+
// lib/solvers/AvailableNetOrientationSolver/traces.ts
|
|
5166
|
+
var getPinMap = (inputProblem) => {
|
|
5167
|
+
const pinMap = {};
|
|
5168
|
+
for (const chip of inputProblem.chips) {
|
|
5169
|
+
for (const pin of chip.pins) {
|
|
5170
|
+
pinMap[pin.pinId] = { ...pin, chipId: chip.chipId };
|
|
5171
|
+
}
|
|
5172
|
+
}
|
|
5173
|
+
return pinMap;
|
|
5174
|
+
};
|
|
5175
|
+
var getTracePins = (label, pinMap) => {
|
|
5176
|
+
const pins = label.pinIds.flatMap((pinId) => {
|
|
5177
|
+
const pin = pinMap[pinId];
|
|
5178
|
+
return pin ? [pin] : [];
|
|
5179
|
+
});
|
|
5180
|
+
if (pins.length >= 2) return [pins[0], pins[1]];
|
|
5181
|
+
if (pins.length === 1) return [pins[0], pins[0]];
|
|
5182
|
+
const syntheticPin = {
|
|
5183
|
+
pinId: `${label.globalConnNetId}-netlabel-anchor`,
|
|
5184
|
+
x: label.anchorPoint.x,
|
|
5185
|
+
y: label.anchorPoint.y,
|
|
5186
|
+
chipId: "available-net-orientation"
|
|
5187
|
+
};
|
|
5188
|
+
return [syntheticPin, syntheticPin];
|
|
5189
|
+
};
|
|
5190
|
+
var toNetLabelPlacementPatch = (candidate) => ({
|
|
5191
|
+
orientation: candidate.orientation,
|
|
5192
|
+
anchorPoint: candidate.anchorPoint,
|
|
5193
|
+
center: candidate.center,
|
|
5194
|
+
width: candidate.width,
|
|
5195
|
+
height: candidate.height
|
|
5196
|
+
});
|
|
5197
|
+
|
|
5198
|
+
// lib/utils/dir.ts
|
|
5199
|
+
var dir = (facingDirection) => {
|
|
5200
|
+
switch (facingDirection) {
|
|
5201
|
+
case "x+":
|
|
5202
|
+
return { x: 1, y: 0 };
|
|
5203
|
+
case "x-":
|
|
5204
|
+
return { x: -1, y: 0 };
|
|
5205
|
+
case "y+":
|
|
5206
|
+
return { x: 0, y: 1 };
|
|
5207
|
+
case "y-":
|
|
5208
|
+
return { x: 0, y: -1 };
|
|
5209
|
+
}
|
|
5210
|
+
throw new Error(`Invalid facing direction: ${facingDirection}`);
|
|
5211
|
+
};
|
|
5212
|
+
|
|
5165
5213
|
// lib/solvers/Example28Solver/types.ts
|
|
5166
5214
|
var EPS7 = 1e-9;
|
|
5167
5215
|
|
|
@@ -5369,24 +5417,8 @@ var moveAttachedLabelsToReroutedTrace = ({
|
|
|
5369
5417
|
};
|
|
5370
5418
|
});
|
|
5371
5419
|
|
|
5372
|
-
// lib/utils/dir.ts
|
|
5373
|
-
var dir = (facingDirection) => {
|
|
5374
|
-
switch (facingDirection) {
|
|
5375
|
-
case "x+":
|
|
5376
|
-
return { x: 1, y: 0 };
|
|
5377
|
-
case "x-":
|
|
5378
|
-
return { x: -1, y: 0 };
|
|
5379
|
-
case "y+":
|
|
5380
|
-
return { x: 0, y: 1 };
|
|
5381
|
-
case "y-":
|
|
5382
|
-
return { x: 0, y: -1 };
|
|
5383
|
-
}
|
|
5384
|
-
throw new Error(`Invalid facing direction: ${facingDirection}`);
|
|
5385
|
-
};
|
|
5386
|
-
|
|
5387
5420
|
// lib/solvers/Example28Solver/reroute.ts
|
|
5388
|
-
var
|
|
5389
|
-
var LABEL_HUG_CLEARANCE = 1e-3;
|
|
5421
|
+
var LABEL_CLEARANCE = 0.1;
|
|
5390
5422
|
var findBestReroutePath = ({
|
|
5391
5423
|
trace,
|
|
5392
5424
|
obstacleLabel,
|
|
@@ -5447,7 +5479,7 @@ var generateRerouteCandidateResults = ({
|
|
|
5447
5479
|
trace,
|
|
5448
5480
|
label,
|
|
5449
5481
|
problem: inputProblem,
|
|
5450
|
-
paddingBuffer:
|
|
5482
|
+
paddingBuffer: LABEL_CLEARANCE,
|
|
5451
5483
|
detourCount: 0
|
|
5452
5484
|
}),
|
|
5453
5485
|
...generateEndpointDetourCandidates(trace, label)
|
|
@@ -5513,8 +5545,10 @@ var generateEndpointDetourCandidates = (trace, label) => {
|
|
|
5513
5545
|
const start = trace.tracePath[0];
|
|
5514
5546
|
const end = trace.tracePath[trace.tracePath.length - 1];
|
|
5515
5547
|
if (!start || !end) return [];
|
|
5548
|
+
const startExit = trace.tracePath[1] ?? start;
|
|
5549
|
+
const endEntry = trace.tracePath[trace.tracePath.length - 2] ?? end;
|
|
5516
5550
|
const bounds = getRectBounds(label.center, label.width, label.height);
|
|
5517
|
-
const padding =
|
|
5551
|
+
const padding = LABEL_CLEARANCE;
|
|
5518
5552
|
const labelDirection = dir(label.orientation);
|
|
5519
5553
|
const labelSideX = labelDirection.x < 0 ? bounds.minX - padding : bounds.maxX + padding;
|
|
5520
5554
|
const oppositeSideX = labelDirection.x < 0 ? bounds.maxX + padding : bounds.minX - padding;
|
|
@@ -5525,18 +5559,22 @@ var generateEndpointDetourCandidates = (trace, label) => {
|
|
|
5525
5559
|
candidates.push(
|
|
5526
5560
|
[
|
|
5527
5561
|
start,
|
|
5528
|
-
|
|
5562
|
+
startExit,
|
|
5563
|
+
{ x: startExit.x, y: topY },
|
|
5529
5564
|
{ x: sideX, y: topY },
|
|
5530
5565
|
{ x: sideX, y: bottomY },
|
|
5531
|
-
{ x:
|
|
5566
|
+
{ x: endEntry.x, y: bottomY },
|
|
5567
|
+
endEntry,
|
|
5532
5568
|
end
|
|
5533
5569
|
],
|
|
5534
5570
|
[
|
|
5535
5571
|
start,
|
|
5536
|
-
|
|
5572
|
+
startExit,
|
|
5573
|
+
{ x: startExit.x, y: bottomY },
|
|
5537
5574
|
{ x: sideX, y: bottomY },
|
|
5538
5575
|
{ x: sideX, y: topY },
|
|
5539
|
-
{ x:
|
|
5576
|
+
{ x: endEntry.x, y: topY },
|
|
5577
|
+
endEntry,
|
|
5540
5578
|
end
|
|
5541
5579
|
]
|
|
5542
5580
|
);
|
|
@@ -5547,30 +5585,36 @@ var generateLabelHugCandidates = (trace, label) => {
|
|
|
5547
5585
|
const start = trace.tracePath[0];
|
|
5548
5586
|
const end = trace.tracePath[trace.tracePath.length - 1];
|
|
5549
5587
|
if (!start || !end) return [];
|
|
5588
|
+
const startExit = trace.tracePath[1] ?? start;
|
|
5589
|
+
const endEntry = trace.tracePath[trace.tracePath.length - 2] ?? end;
|
|
5550
5590
|
const labelDirection = dir(label.orientation);
|
|
5551
5591
|
if (labelDirection.x === 0) return [];
|
|
5552
5592
|
const bounds = getRectBounds(label.center, label.width, label.height);
|
|
5553
|
-
const sideX = labelDirection.x < 0 ? bounds.minX -
|
|
5554
|
-
const topY = bounds.maxY +
|
|
5555
|
-
const bottomY = bounds.minY -
|
|
5556
|
-
const startsAboveEnd =
|
|
5593
|
+
const sideX = labelDirection.x < 0 ? bounds.minX - LABEL_CLEARANCE : bounds.maxX + LABEL_CLEARANCE;
|
|
5594
|
+
const topY = bounds.maxY + LABEL_CLEARANCE;
|
|
5595
|
+
const bottomY = bounds.minY - LABEL_CLEARANCE;
|
|
5596
|
+
const startsAboveEnd = startExit.y >= endEntry.y;
|
|
5557
5597
|
const firstY = startsAboveEnd ? topY : bottomY;
|
|
5558
5598
|
const secondY = startsAboveEnd ? bottomY : topY;
|
|
5559
5599
|
return [
|
|
5560
5600
|
[
|
|
5561
5601
|
start,
|
|
5562
|
-
|
|
5602
|
+
startExit,
|
|
5603
|
+
{ x: startExit.x, y: firstY },
|
|
5563
5604
|
{ x: sideX, y: firstY },
|
|
5564
5605
|
{ x: sideX, y: secondY },
|
|
5565
|
-
{ x:
|
|
5606
|
+
{ x: endEntry.x, y: secondY },
|
|
5607
|
+
endEntry,
|
|
5566
5608
|
end
|
|
5567
5609
|
],
|
|
5568
5610
|
[
|
|
5569
5611
|
start,
|
|
5570
|
-
|
|
5612
|
+
startExit,
|
|
5613
|
+
{ x: startExit.x, y: secondY },
|
|
5571
5614
|
{ x: sideX, y: secondY },
|
|
5572
5615
|
{ x: sideX, y: firstY },
|
|
5573
|
-
{ x:
|
|
5616
|
+
{ x: endEntry.x, y: firstY },
|
|
5617
|
+
endEntry,
|
|
5574
5618
|
end
|
|
5575
5619
|
]
|
|
5576
5620
|
];
|
|
@@ -5625,9 +5669,9 @@ var generateHorizontalSegmentPushCandidate = (trace, label) => {
|
|
|
5625
5669
|
if (Math.abs(previousAnchor.y - verticalStart.y) >= 1e-9 || Math.abs(verticalEnd.y - nextAnchor.y) >= 1e-9) {
|
|
5626
5670
|
return null;
|
|
5627
5671
|
}
|
|
5628
|
-
let segmentPushX = bounds.minX -
|
|
5672
|
+
let segmentPushX = bounds.minX - LABEL_CLEARANCE;
|
|
5629
5673
|
if (labelDirection.x > 0) {
|
|
5630
|
-
segmentPushX = bounds.maxX +
|
|
5674
|
+
segmentPushX = bounds.maxX + LABEL_CLEARANCE;
|
|
5631
5675
|
}
|
|
5632
5676
|
const segmentPushStartY = getClearedHorizontalY({
|
|
5633
5677
|
start: previousAnchor,
|
|
@@ -5665,9 +5709,9 @@ var getClearedHorizontalY = ({
|
|
|
5665
5709
|
if (!segmentIntersectsRect2(start, end, labelBounds)) return start.y;
|
|
5666
5710
|
const labelCenterY = (labelBounds.minY + labelBounds.maxY) / 2;
|
|
5667
5711
|
if (start.y >= labelCenterY) {
|
|
5668
|
-
return labelBounds.maxY +
|
|
5712
|
+
return labelBounds.maxY + LABEL_CLEARANCE;
|
|
5669
5713
|
}
|
|
5670
|
-
return labelBounds.minY -
|
|
5714
|
+
return labelBounds.minY - LABEL_CLEARANCE;
|
|
5671
5715
|
};
|
|
5672
5716
|
var markSelectedCandidate = (candidateResults, bestPath) => {
|
|
5673
5717
|
if (!bestPath) return;
|
|
@@ -5800,6 +5844,9 @@ ${label.netId ?? label.globalConnNetId}`
|
|
|
5800
5844
|
};
|
|
5801
5845
|
|
|
5802
5846
|
// lib/solvers/Example28Solver/Example28Solver.ts
|
|
5847
|
+
var LABEL_OUTWARD_STEP = 0.1;
|
|
5848
|
+
var LABEL_MAX_OUTWARD_STEPS = 10;
|
|
5849
|
+
var LABEL_TRACE_CLEARANCE = 0.1;
|
|
5803
5850
|
var Example28Solver = class extends BaseSolver {
|
|
5804
5851
|
inputProblem;
|
|
5805
5852
|
traces;
|
|
@@ -5810,6 +5857,7 @@ var Example28Solver = class extends BaseSolver {
|
|
|
5810
5857
|
currentOverlap = null;
|
|
5811
5858
|
currentCandidateResults = [];
|
|
5812
5859
|
chipObstacles;
|
|
5860
|
+
pinMap;
|
|
5813
5861
|
constructor(params) {
|
|
5814
5862
|
super();
|
|
5815
5863
|
this.inputProblem = params.inputProblem;
|
|
@@ -5818,6 +5866,7 @@ var Example28Solver = class extends BaseSolver {
|
|
|
5818
5866
|
this.outputTraces = [...params.traces];
|
|
5819
5867
|
this.outputNetLabelPlacements = [...params.netLabelPlacements];
|
|
5820
5868
|
this.chipObstacles = getObstacleRects(params.inputProblem);
|
|
5869
|
+
this.pinMap = getPinMap(params.inputProblem);
|
|
5821
5870
|
this.initializeQueuedOverlaps();
|
|
5822
5871
|
this.currentOverlap = this.queuedOverlaps[0] ?? null;
|
|
5823
5872
|
}
|
|
@@ -5900,6 +5949,7 @@ var Example28Solver = class extends BaseSolver {
|
|
|
5900
5949
|
);
|
|
5901
5950
|
if (traceIndex === -1) return;
|
|
5902
5951
|
const currentTrace = this.outputTraces[traceIndex];
|
|
5952
|
+
if (this.tryMoveLabelOutward(overlap.label)) return;
|
|
5903
5953
|
const rerouteResult = findBestReroutePath({
|
|
5904
5954
|
trace: currentTrace,
|
|
5905
5955
|
obstacleLabel: overlap.label,
|
|
@@ -5922,6 +5972,62 @@ var Example28Solver = class extends BaseSolver {
|
|
|
5922
5972
|
netLabelPlacements: this.outputNetLabelPlacements
|
|
5923
5973
|
});
|
|
5924
5974
|
}
|
|
5975
|
+
tryMoveLabelOutward(labelToMove) {
|
|
5976
|
+
const labelIndex = this.outputNetLabelPlacements.findIndex(
|
|
5977
|
+
(label2) => label2.globalConnNetId === labelToMove.globalConnNetId && label2.anchorPoint.x === labelToMove.anchorPoint.x && label2.anchorPoint.y === labelToMove.anchorPoint.y && label2.pinIds.join(",") === labelToMove.pinIds.join(",")
|
|
5978
|
+
);
|
|
5979
|
+
if (labelIndex === -1) return false;
|
|
5980
|
+
const label = this.outputNetLabelPlacements[labelIndex];
|
|
5981
|
+
if (label.mspConnectionPairIds.length > 0) return false;
|
|
5982
|
+
if (label.pinIds.length !== 1) return false;
|
|
5983
|
+
if (this.outputNetLabelPlacements.filter(
|
|
5984
|
+
(otherLabel) => otherLabel.globalConnNetId === label.globalConnNetId
|
|
5985
|
+
).length !== 1) {
|
|
5986
|
+
return false;
|
|
5987
|
+
}
|
|
5988
|
+
const outward = dir(label.orientation);
|
|
5989
|
+
if (outward.x === 0 && outward.y === 0) return false;
|
|
5990
|
+
for (let step = 1; step <= LABEL_MAX_OUTWARD_STEPS; step++) {
|
|
5991
|
+
const distance3 = step * LABEL_OUTWARD_STEP;
|
|
5992
|
+
const candidate = {
|
|
5993
|
+
...label,
|
|
5994
|
+
anchorPoint: {
|
|
5995
|
+
x: label.anchorPoint.x + outward.x * distance3,
|
|
5996
|
+
y: label.anchorPoint.y + outward.y * distance3
|
|
5997
|
+
},
|
|
5998
|
+
center: {
|
|
5999
|
+
x: label.center.x + outward.x * distance3,
|
|
6000
|
+
y: label.center.y + outward.y * distance3
|
|
6001
|
+
}
|
|
6002
|
+
};
|
|
6003
|
+
const candidateWithClearance = {
|
|
6004
|
+
...candidate,
|
|
6005
|
+
width: candidate.width + LABEL_TRACE_CLEARANCE * 2,
|
|
6006
|
+
height: candidate.height + LABEL_TRACE_CLEARANCE * 2
|
|
6007
|
+
};
|
|
6008
|
+
if (detectTraceLabelOverlap({
|
|
6009
|
+
traces: this.outputTraces,
|
|
6010
|
+
netLabels: [candidateWithClearance]
|
|
6011
|
+
}).length > 0) {
|
|
6012
|
+
continue;
|
|
6013
|
+
}
|
|
6014
|
+
const connectorTrace = createPortOnlyLabelConnectorTrace({
|
|
6015
|
+
label,
|
|
6016
|
+
movedLabel: candidate,
|
|
6017
|
+
pinMap: this.pinMap
|
|
6018
|
+
});
|
|
6019
|
+
if (detectTraceLabelOverlap({
|
|
6020
|
+
traces: [connectorTrace],
|
|
6021
|
+
netLabels: this.outputNetLabelPlacements
|
|
6022
|
+
}).length > 0) {
|
|
6023
|
+
continue;
|
|
6024
|
+
}
|
|
6025
|
+
this.outputNetLabelPlacements[labelIndex] = candidate;
|
|
6026
|
+
this.outputTraces.push(connectorTrace);
|
|
6027
|
+
return true;
|
|
6028
|
+
}
|
|
6029
|
+
return false;
|
|
6030
|
+
}
|
|
5925
6031
|
visualize() {
|
|
5926
6032
|
return visualizeExample28Solver({
|
|
5927
6033
|
inputProblem: this.inputProblem,
|
|
@@ -5933,6 +6039,24 @@ var Example28Solver = class extends BaseSolver {
|
|
|
5933
6039
|
});
|
|
5934
6040
|
}
|
|
5935
6041
|
};
|
|
6042
|
+
var getPortOnlyLabelConnectorMspPairId = (label) => `port-only-label-connector-${label.globalConnNetId}-${label.pinIds[0]}`;
|
|
6043
|
+
var createPortOnlyLabelConnectorTrace = ({
|
|
6044
|
+
label,
|
|
6045
|
+
movedLabel,
|
|
6046
|
+
pinMap
|
|
6047
|
+
}) => {
|
|
6048
|
+
const mspPairId = getPortOnlyLabelConnectorMspPairId(label);
|
|
6049
|
+
return {
|
|
6050
|
+
mspPairId,
|
|
6051
|
+
dcConnNetId: label.dcConnNetId ?? label.globalConnNetId,
|
|
6052
|
+
globalConnNetId: label.globalConnNetId,
|
|
6053
|
+
userNetId: label.netId,
|
|
6054
|
+
pins: getTracePins(label, pinMap),
|
|
6055
|
+
tracePath: [label.anchorPoint, movedLabel.anchorPoint],
|
|
6056
|
+
mspConnectionPairIds: [mspPairId],
|
|
6057
|
+
pinIds: label.pinIds
|
|
6058
|
+
};
|
|
6059
|
+
};
|
|
5936
6060
|
|
|
5937
6061
|
// lib/solvers/AvailableNetOrientationSolver/constants.ts
|
|
5938
6062
|
var LABEL_SEARCH_STEP = 0.05;
|
|
@@ -6046,39 +6170,6 @@ var getMaxSearchDistance = (inputProblem) => {
|
|
|
6046
6170
|
return maxChipWidth * 3;
|
|
6047
6171
|
};
|
|
6048
6172
|
|
|
6049
|
-
// lib/solvers/AvailableNetOrientationSolver/traces.ts
|
|
6050
|
-
var getPinMap = (inputProblem) => {
|
|
6051
|
-
const pinMap = {};
|
|
6052
|
-
for (const chip of inputProblem.chips) {
|
|
6053
|
-
for (const pin of chip.pins) {
|
|
6054
|
-
pinMap[pin.pinId] = { ...pin, chipId: chip.chipId };
|
|
6055
|
-
}
|
|
6056
|
-
}
|
|
6057
|
-
return pinMap;
|
|
6058
|
-
};
|
|
6059
|
-
var getTracePins = (label, pinMap) => {
|
|
6060
|
-
const pins = label.pinIds.flatMap((pinId) => {
|
|
6061
|
-
const pin = pinMap[pinId];
|
|
6062
|
-
return pin ? [pin] : [];
|
|
6063
|
-
});
|
|
6064
|
-
if (pins.length >= 2) return [pins[0], pins[1]];
|
|
6065
|
-
if (pins.length === 1) return [pins[0], pins[0]];
|
|
6066
|
-
const syntheticPin = {
|
|
6067
|
-
pinId: `${label.globalConnNetId}-netlabel-anchor`,
|
|
6068
|
-
x: label.anchorPoint.x,
|
|
6069
|
-
y: label.anchorPoint.y,
|
|
6070
|
-
chipId: "available-net-orientation"
|
|
6071
|
-
};
|
|
6072
|
-
return [syntheticPin, syntheticPin];
|
|
6073
|
-
};
|
|
6074
|
-
var toNetLabelPlacementPatch = (candidate) => ({
|
|
6075
|
-
orientation: candidate.orientation,
|
|
6076
|
-
anchorPoint: candidate.anchorPoint,
|
|
6077
|
-
center: candidate.center,
|
|
6078
|
-
width: candidate.width,
|
|
6079
|
-
height: candidate.height
|
|
6080
|
-
});
|
|
6081
|
-
|
|
6082
6173
|
// lib/solvers/AvailableNetOrientationSolver/visualize.ts
|
|
6083
6174
|
var visualizeAvailableNetOrientationSolver = (params) => {
|
|
6084
6175
|
const graphics = visualizeInputProblem(params.inputProblem);
|
|
@@ -6167,7 +6258,7 @@ var ensureGraphicsArrays = (graphics) => {
|
|
|
6167
6258
|
};
|
|
6168
6259
|
|
|
6169
6260
|
// lib/solvers/AvailableNetOrientationSolver/AvailableNetOrientationSolver.ts
|
|
6170
|
-
var
|
|
6261
|
+
var LABEL_TRACE_CLEARANCE2 = 0.1;
|
|
6171
6262
|
var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
6172
6263
|
inputProblem;
|
|
6173
6264
|
traces;
|
|
@@ -6725,10 +6816,10 @@ var AvailableNetOrientationSolver = class extends BaseSolver {
|
|
|
6725
6816
|
}
|
|
6726
6817
|
getLabelTraceClearanceBounds(bounds) {
|
|
6727
6818
|
return {
|
|
6728
|
-
minX: bounds.minX -
|
|
6729
|
-
minY: bounds.minY -
|
|
6730
|
-
maxX: bounds.maxX +
|
|
6731
|
-
maxY: bounds.maxY +
|
|
6819
|
+
minX: bounds.minX - LABEL_TRACE_CLEARANCE2,
|
|
6820
|
+
minY: bounds.minY - LABEL_TRACE_CLEARANCE2,
|
|
6821
|
+
maxX: bounds.maxX + LABEL_TRACE_CLEARANCE2,
|
|
6822
|
+
maxY: bounds.maxY + LABEL_TRACE_CLEARANCE2
|
|
6732
6823
|
};
|
|
6733
6824
|
}
|
|
6734
6825
|
shouldCheckTraceClearanceForLabel(label) {
|
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
import type { GraphicsObject } from "graphics-debug"
|
|
2
|
+
import {
|
|
3
|
+
getPinMap,
|
|
4
|
+
getTracePins,
|
|
5
|
+
} from "lib/solvers/AvailableNetOrientationSolver/traces"
|
|
2
6
|
import { BaseSolver } from "lib/solvers/BaseSolver/BaseSolver"
|
|
3
7
|
import type { NetLabelPlacement } from "lib/solvers/NetLabelPlacementSolver/NetLabelPlacementSolver"
|
|
4
|
-
import { getObstacleRects } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/rect"
|
|
5
8
|
import type { SolvedTracePath } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceLinesSolver"
|
|
9
|
+
import { getObstacleRects } from "lib/solvers/SchematicTraceLinesSolver/SchematicTraceSingleLineSolver2/rect"
|
|
6
10
|
import {
|
|
7
11
|
detectTraceLabelOverlap,
|
|
8
12
|
type TraceLabelOverlap,
|
|
9
13
|
} from "lib/solvers/TraceLabelOverlapAvoidanceSolver/detectTraceLabelOverlap"
|
|
10
|
-
import type { InputProblem } from "lib/types/InputProblem"
|
|
14
|
+
import type { InputPin, InputProblem } from "lib/types/InputProblem"
|
|
15
|
+
import { dir } from "lib/utils/dir"
|
|
11
16
|
import { moveAttachedLabelsToReroutedTrace } from "./labelMovement"
|
|
12
17
|
import { findBestReroutePath } from "./reroute"
|
|
13
18
|
import type { Example28SolverParams, RerouteCandidateResult } from "./types"
|
|
14
19
|
import { visualizeExample28Solver } from "./visualize"
|
|
15
20
|
|
|
21
|
+
const LABEL_OUTWARD_STEP = 0.1
|
|
22
|
+
const LABEL_MAX_OUTWARD_STEPS = 10
|
|
23
|
+
const LABEL_TRACE_CLEARANCE = 0.1
|
|
24
|
+
|
|
16
25
|
export class Example28Solver extends BaseSolver {
|
|
17
26
|
inputProblem: InputProblem
|
|
18
27
|
traces: SolvedTracePath[]
|
|
@@ -25,6 +34,7 @@ export class Example28Solver extends BaseSolver {
|
|
|
25
34
|
currentCandidateResults: RerouteCandidateResult[] = []
|
|
26
35
|
|
|
27
36
|
private chipObstacles: ReturnType<typeof getObstacleRects>
|
|
37
|
+
private pinMap: Record<string, InputPin & { chipId: string }>
|
|
28
38
|
|
|
29
39
|
constructor(params: Example28SolverParams) {
|
|
30
40
|
super()
|
|
@@ -34,6 +44,7 @@ export class Example28Solver extends BaseSolver {
|
|
|
34
44
|
this.outputTraces = [...params.traces]
|
|
35
45
|
this.outputNetLabelPlacements = [...params.netLabelPlacements]
|
|
36
46
|
this.chipObstacles = getObstacleRects(params.inputProblem)
|
|
47
|
+
this.pinMap = getPinMap(params.inputProblem)
|
|
37
48
|
this.initializeQueuedOverlaps()
|
|
38
49
|
this.currentOverlap = this.queuedOverlaps[0] ?? null
|
|
39
50
|
}
|
|
@@ -144,6 +155,8 @@ export class Example28Solver extends BaseSolver {
|
|
|
144
155
|
if (traceIndex === -1) return
|
|
145
156
|
|
|
146
157
|
const currentTrace = this.outputTraces[traceIndex]!
|
|
158
|
+
if (this.tryMoveLabelOutward(overlap.label)) return
|
|
159
|
+
|
|
147
160
|
const rerouteResult = findBestReroutePath({
|
|
148
161
|
trace: currentTrace,
|
|
149
162
|
obstacleLabel: overlap.label,
|
|
@@ -169,6 +182,79 @@ export class Example28Solver extends BaseSolver {
|
|
|
169
182
|
})
|
|
170
183
|
}
|
|
171
184
|
|
|
185
|
+
private tryMoveLabelOutward(labelToMove: NetLabelPlacement) {
|
|
186
|
+
const labelIndex = this.outputNetLabelPlacements.findIndex(
|
|
187
|
+
(label) =>
|
|
188
|
+
label.globalConnNetId === labelToMove.globalConnNetId &&
|
|
189
|
+
label.anchorPoint.x === labelToMove.anchorPoint.x &&
|
|
190
|
+
label.anchorPoint.y === labelToMove.anchorPoint.y &&
|
|
191
|
+
label.pinIds.join(",") === labelToMove.pinIds.join(","),
|
|
192
|
+
)
|
|
193
|
+
if (labelIndex === -1) return false
|
|
194
|
+
|
|
195
|
+
const label = this.outputNetLabelPlacements[labelIndex]!
|
|
196
|
+
if (label.mspConnectionPairIds.length > 0) return false
|
|
197
|
+
if (label.pinIds.length !== 1) return false
|
|
198
|
+
if (
|
|
199
|
+
this.outputNetLabelPlacements.filter(
|
|
200
|
+
(otherLabel) => otherLabel.globalConnNetId === label.globalConnNetId,
|
|
201
|
+
).length !== 1
|
|
202
|
+
) {
|
|
203
|
+
return false
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const outward = dir(label.orientation)
|
|
207
|
+
if (outward.x === 0 && outward.y === 0) return false
|
|
208
|
+
|
|
209
|
+
for (let step = 1; step <= LABEL_MAX_OUTWARD_STEPS; step++) {
|
|
210
|
+
const distance = step * LABEL_OUTWARD_STEP
|
|
211
|
+
const candidate = {
|
|
212
|
+
...label,
|
|
213
|
+
anchorPoint: {
|
|
214
|
+
x: label.anchorPoint.x + outward.x * distance,
|
|
215
|
+
y: label.anchorPoint.y + outward.y * distance,
|
|
216
|
+
},
|
|
217
|
+
center: {
|
|
218
|
+
x: label.center.x + outward.x * distance,
|
|
219
|
+
y: label.center.y + outward.y * distance,
|
|
220
|
+
},
|
|
221
|
+
}
|
|
222
|
+
const candidateWithClearance = {
|
|
223
|
+
...candidate,
|
|
224
|
+
width: candidate.width + LABEL_TRACE_CLEARANCE * 2,
|
|
225
|
+
height: candidate.height + LABEL_TRACE_CLEARANCE * 2,
|
|
226
|
+
}
|
|
227
|
+
if (
|
|
228
|
+
detectTraceLabelOverlap({
|
|
229
|
+
traces: this.outputTraces,
|
|
230
|
+
netLabels: [candidateWithClearance],
|
|
231
|
+
}).length > 0
|
|
232
|
+
) {
|
|
233
|
+
continue
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const connectorTrace = createPortOnlyLabelConnectorTrace({
|
|
237
|
+
label,
|
|
238
|
+
movedLabel: candidate,
|
|
239
|
+
pinMap: this.pinMap,
|
|
240
|
+
})
|
|
241
|
+
if (
|
|
242
|
+
detectTraceLabelOverlap({
|
|
243
|
+
traces: [connectorTrace],
|
|
244
|
+
netLabels: this.outputNetLabelPlacements,
|
|
245
|
+
}).length > 0
|
|
246
|
+
) {
|
|
247
|
+
continue
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
this.outputNetLabelPlacements[labelIndex] = candidate
|
|
251
|
+
this.outputTraces.push(connectorTrace)
|
|
252
|
+
return true
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return false
|
|
256
|
+
}
|
|
257
|
+
|
|
172
258
|
override visualize(): GraphicsObject {
|
|
173
259
|
return visualizeExample28Solver({
|
|
174
260
|
inputProblem: this.inputProblem,
|
|
@@ -180,3 +266,29 @@ export class Example28Solver extends BaseSolver {
|
|
|
180
266
|
})
|
|
181
267
|
}
|
|
182
268
|
}
|
|
269
|
+
|
|
270
|
+
const getPortOnlyLabelConnectorMspPairId = (label: NetLabelPlacement) =>
|
|
271
|
+
`port-only-label-connector-${label.globalConnNetId}-${label.pinIds[0]}`
|
|
272
|
+
|
|
273
|
+
const createPortOnlyLabelConnectorTrace = ({
|
|
274
|
+
label,
|
|
275
|
+
movedLabel,
|
|
276
|
+
pinMap,
|
|
277
|
+
}: {
|
|
278
|
+
label: NetLabelPlacement
|
|
279
|
+
movedLabel: NetLabelPlacement
|
|
280
|
+
pinMap: Record<string, InputPin & { chipId: string }>
|
|
281
|
+
}): SolvedTracePath => {
|
|
282
|
+
const mspPairId = getPortOnlyLabelConnectorMspPairId(label)
|
|
283
|
+
|
|
284
|
+
return {
|
|
285
|
+
mspPairId,
|
|
286
|
+
dcConnNetId: label.dcConnNetId ?? label.globalConnNetId,
|
|
287
|
+
globalConnNetId: label.globalConnNetId,
|
|
288
|
+
userNetId: label.netId,
|
|
289
|
+
pins: getTracePins(label, pinMap),
|
|
290
|
+
tracePath: [label.anchorPoint, movedLabel.anchorPoint],
|
|
291
|
+
mspConnectionPairIds: [mspPairId],
|
|
292
|
+
pinIds: label.pinIds,
|
|
293
|
+
}
|
|
294
|
+
}
|