@tscircuit/schematic-trace-solver 0.0.150 → 0.0.151
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/README.md +6 -4
- package/dist/index.d.ts +36 -2
- package/dist/index.js +359 -64
- package/lib/solvers/InlineNetLabelSolver/InlineNetLabelSolver.ts +111 -82
- package/lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts +338 -0
- package/lib/solvers/NetLabelTraceRecovery/getTraceRecoveryConnectivityMaps.ts +33 -0
- package/lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts +15 -0
- package/package.json +1 -1
- package/tests/examples/__snapshots__/example51.snap.svg +5 -17
- package/tests/repros/__snapshots__/board1096-usb-label-overlap-iteration.snap.svg +3 -3
package/README.md
CHANGED
|
@@ -48,10 +48,12 @@ decides which connections deserve one; the solver only honors the request when
|
|
|
48
48
|
the connection actually got routed, since there is nothing to run parallel to
|
|
49
49
|
otherwise.
|
|
50
50
|
|
|
51
|
-
The `InlineNetLabelSolver`
|
|
52
|
-
|
|
53
|
-
`
|
|
54
|
-
|
|
51
|
+
The `InlineNetLabelSolver` exposes `inlineNetLabelPlacements`. A net that
|
|
52
|
+
receives an inline label has its anchored `NetLabelPlacement` removed from
|
|
53
|
+
`getOutput().netLabelPlacements`, so a net is never labeled twice.
|
|
54
|
+
`NetLabelToTraceSolver` then replaces pairs of port-only fallback labels with
|
|
55
|
+
real traces whenever the router finds a clear path. Its `getOutput()` is the
|
|
56
|
+
pipeline's final output.
|
|
55
57
|
|
|
56
58
|
```tsx
|
|
57
59
|
directConnections: [
|
package/dist/index.d.ts
CHANGED
|
@@ -1266,6 +1266,12 @@ interface InlineNetLabelSolverInput {
|
|
|
1266
1266
|
traces: SolvedTracePath[];
|
|
1267
1267
|
netLabelPlacements: NetLabelPlacement[];
|
|
1268
1268
|
}
|
|
1269
|
+
interface InlineNetLabelOutput {
|
|
1270
|
+
inputProblem: InputProblem;
|
|
1271
|
+
traces: SolvedTracePath[];
|
|
1272
|
+
netLabelPlacements: NetLabelPlacement[];
|
|
1273
|
+
inlineNetLabelPlacements: InlineNetLabelPlacement[];
|
|
1274
|
+
}
|
|
1269
1275
|
type InlineEligibleConnection = InputDirectConnection | InputNetConnection;
|
|
1270
1276
|
/**
|
|
1271
1277
|
* Places "inline net labels" - net names drawn alongside the trace they belong
|
|
@@ -1322,12 +1328,39 @@ declare class InlineNetLabelSolver extends BaseSolver {
|
|
|
1322
1328
|
};
|
|
1323
1329
|
visualize(): GraphicsObject;
|
|
1324
1330
|
}
|
|
1331
|
+
declare const visualizeInlineNetLabelOutput: ({ inputProblem, traces, netLabelPlacements, inlineNetLabelPlacements, }: InlineNetLabelOutput) => GraphicsObject;
|
|
1325
1332
|
/**
|
|
1326
1333
|
* Mirrors the net label text width used by @tscircuit/core so a label that core
|
|
1327
1334
|
* did not measure for us still reserves a sane amount of space.
|
|
1328
1335
|
*/
|
|
1329
1336
|
declare const estimateInlineNetLabelWidth: (text: string, fontSize?: number) => number;
|
|
1330
1337
|
|
|
1338
|
+
declare class NetLabelToTraceSolver extends BaseSolver {
|
|
1339
|
+
private input;
|
|
1340
|
+
inputProblem: InputProblem;
|
|
1341
|
+
outputTraces: SolvedTracePath[];
|
|
1342
|
+
outputNetLabelPlacements: NetLabelPlacement[];
|
|
1343
|
+
private chipMap;
|
|
1344
|
+
private pinMap;
|
|
1345
|
+
private queuedCandidates;
|
|
1346
|
+
private currentCandidate;
|
|
1347
|
+
activeSubSolver: SchematicTraceSingleLineSolver2 | null;
|
|
1348
|
+
constructor(input: InlineNetLabelOutput);
|
|
1349
|
+
getConstructorParams(): [InlineNetLabelOutput];
|
|
1350
|
+
private isEligiblePortOnlyDirectConnectionLabel;
|
|
1351
|
+
private buildCandidatePairs;
|
|
1352
|
+
private isSupersededConnectorTrace;
|
|
1353
|
+
private routeIntersectsRemainingLabels;
|
|
1354
|
+
private tryAcceptCurrentRoute;
|
|
1355
|
+
_step(): void;
|
|
1356
|
+
getOutput(): {
|
|
1357
|
+
traces: SolvedTracePath[];
|
|
1358
|
+
netLabelPlacements: NetLabelPlacement[];
|
|
1359
|
+
inlineNetLabelPlacements: InlineNetLabelPlacement[];
|
|
1360
|
+
};
|
|
1361
|
+
visualize(): GraphicsObject;
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1331
1364
|
/**
|
|
1332
1365
|
* Pipeline solver that runs a series of solvers to find the best schematic layout.
|
|
1333
1366
|
* Coordinates the entire layout process from chip partitioning through final packing.
|
|
@@ -1368,13 +1401,14 @@ declare class SchematicTracePipelineSolver extends BaseSolver {
|
|
|
1368
1401
|
finalTraceElbowTransitionSimplificationSolver?: TraceElbowTransitionSimplificationSolver;
|
|
1369
1402
|
sameNetJunctionAlignmentSolver?: SameNetJunctionAlignmentSolver;
|
|
1370
1403
|
inlineNetLabelSolver?: InlineNetLabelSolver;
|
|
1404
|
+
netLabelToTraceSolver?: NetLabelToTraceSolver;
|
|
1371
1405
|
startTimeOfPhase: Record<string, number>;
|
|
1372
1406
|
endTimeOfPhase: Record<string, number>;
|
|
1373
1407
|
timeSpentOnPhase: Record<string, number>;
|
|
1374
1408
|
firstIterationOfPhase: Record<string, number>;
|
|
1375
1409
|
inputProblem: InputProblem;
|
|
1376
1410
|
hideRatsNet: boolean;
|
|
1377
|
-
pipelineDef: (PipelineStep<typeof MspConnectionPairSolver> | PipelineStep<typeof SchematicTraceLinesSolver> | PipelineStep<typeof LongDistancePairSolver> | PipelineStep<typeof UnroutedTraceRecoverySolver> | PipelineStep<typeof TraceOverlapShiftSolver> | PipelineStep<typeof NetLabelPlacementSolver> | PipelineStep<typeof TraceLabelOverlapAvoidanceSolver> | PipelineStep<typeof TraceElbowTransitionSimplificationSolver> | PipelineStep<typeof TraceCleanupSolver> | PipelineStep<typeof Example28Solver> | PipelineStep<typeof AvailableNetOrientationSolver> | PipelineStep<typeof RailNetLabelCornerPlacementSolver> | PipelineStep<typeof TraceAnchoredNetLabelOverlapSolver> | PipelineStep<typeof NetLabelTraceCollisionSolver> | PipelineStep<typeof NetLabelNetLabelCollisionSolver> | PipelineStep<typeof SameNetJunctionAlignmentSolver> | PipelineStep<typeof InlineNetLabelSolver>)[];
|
|
1411
|
+
pipelineDef: (PipelineStep<typeof MspConnectionPairSolver> | PipelineStep<typeof SchematicTraceLinesSolver> | PipelineStep<typeof LongDistancePairSolver> | PipelineStep<typeof UnroutedTraceRecoverySolver> | PipelineStep<typeof TraceOverlapShiftSolver> | PipelineStep<typeof NetLabelPlacementSolver> | PipelineStep<typeof TraceLabelOverlapAvoidanceSolver> | PipelineStep<typeof TraceElbowTransitionSimplificationSolver> | PipelineStep<typeof TraceCleanupSolver> | PipelineStep<typeof Example28Solver> | PipelineStep<typeof AvailableNetOrientationSolver> | PipelineStep<typeof RailNetLabelCornerPlacementSolver> | PipelineStep<typeof TraceAnchoredNetLabelOverlapSolver> | PipelineStep<typeof NetLabelTraceCollisionSolver> | PipelineStep<typeof NetLabelNetLabelCollisionSolver> | PipelineStep<typeof SameNetJunctionAlignmentSolver> | PipelineStep<typeof InlineNetLabelSolver> | PipelineStep<typeof NetLabelToTraceSolver>)[];
|
|
1378
1412
|
constructor(inputProblem: InputProblem, opts?: Options);
|
|
1379
1413
|
getConstructorParams(): ConstructorParameters<typeof SchematicTracePipelineSolver>;
|
|
1380
1414
|
currentPipelineStepIndex: number;
|
|
@@ -1390,4 +1424,4 @@ declare class SchematicTracePipelineSolver extends BaseSolver {
|
|
|
1390
1424
|
preview(): GraphicsObject;
|
|
1391
1425
|
}
|
|
1392
1426
|
|
|
1393
|
-
export { type ChipId, DEFAULT_INLINE_NET_LABEL_HEIGHT, INLINE_NET_LABEL_MAX_SPAN_JOG, INLINE_NET_LABEL_STUB_TRACE_CLEARANCE, INLINE_NET_LABEL_TRACE_MARGIN, type InlineNetLabelPlacement, InlineNetLabelSolver, type InputChip, type InputDirectConnection, type InputNetConnection, type InputPin, type InputProblem, type NetId, type NetLabelPlacement, type PinId, SchematicTracePipelineSolver, SchematicTraceSingleLineSolver2, type SectionId, type TextBoxes, estimateInlineNetLabelWidth };
|
|
1427
|
+
export { type ChipId, DEFAULT_INLINE_NET_LABEL_HEIGHT, INLINE_NET_LABEL_MAX_SPAN_JOG, INLINE_NET_LABEL_STUB_TRACE_CLEARANCE, INLINE_NET_LABEL_TRACE_MARGIN, type InlineNetLabelOutput, type InlineNetLabelPlacement, InlineNetLabelSolver, type InputChip, type InputDirectConnection, type InputNetConnection, type InputPin, type InputProblem, type NetId, type NetLabelPlacement, type PinId, SchematicTracePipelineSolver, SchematicTraceSingleLineSolver2, type SectionId, type TextBoxes, estimateInlineNetLabelWidth, visualizeInlineNetLabelOutput };
|
package/dist/index.js
CHANGED
|
@@ -13606,77 +13606,113 @@ var InlineNetLabelSolver = class extends BaseSolver {
|
|
|
13606
13606
|
return this.buildPostProcessedOutput();
|
|
13607
13607
|
}
|
|
13608
13608
|
visualize() {
|
|
13609
|
-
|
|
13610
|
-
|
|
13611
|
-
|
|
13612
|
-
|
|
13613
|
-
|
|
13614
|
-
|
|
13615
|
-
|
|
13609
|
+
return visualizeInlineNetLabelOutput({
|
|
13610
|
+
inputProblem: this.inputProblem,
|
|
13611
|
+
...this.getOutput()
|
|
13612
|
+
});
|
|
13613
|
+
}
|
|
13614
|
+
};
|
|
13615
|
+
var visualizeInlineNetLabelOutput = ({
|
|
13616
|
+
inputProblem,
|
|
13617
|
+
traces,
|
|
13618
|
+
netLabelPlacements,
|
|
13619
|
+
inlineNetLabelPlacements
|
|
13620
|
+
}) => {
|
|
13621
|
+
const graphics = visualizeInputProblem(inputProblem);
|
|
13622
|
+
graphics.lines ??= [];
|
|
13623
|
+
graphics.rects ??= [];
|
|
13624
|
+
graphics.points ??= [];
|
|
13625
|
+
graphics.texts ??= [];
|
|
13626
|
+
for (const trace of traces) {
|
|
13627
|
+
graphics.lines.push({
|
|
13628
|
+
points: trace.tracePath,
|
|
13629
|
+
strokeColor: "purple"
|
|
13630
|
+
});
|
|
13631
|
+
}
|
|
13632
|
+
for (const label of netLabelPlacements) {
|
|
13633
|
+
graphics.rects.push({
|
|
13634
|
+
center: label.center,
|
|
13635
|
+
width: label.width,
|
|
13636
|
+
height: label.height,
|
|
13637
|
+
fill: getColorFromString(label.globalConnNetId, 0.35),
|
|
13638
|
+
strokeColor: getColorFromString(label.globalConnNetId, 0.9),
|
|
13639
|
+
label: `netId: ${label.netId}
|
|
13640
|
+
globalConnNetId: ${label.globalConnNetId}`
|
|
13641
|
+
});
|
|
13642
|
+
graphics.points.push({
|
|
13643
|
+
x: label.anchorPoint.x,
|
|
13644
|
+
y: label.anchorPoint.y,
|
|
13645
|
+
color: getColorFromString(label.globalConnNetId, 0.9),
|
|
13646
|
+
label: `anchorPoint
|
|
13647
|
+
orientation: ${label.orientation}`
|
|
13648
|
+
});
|
|
13649
|
+
}
|
|
13650
|
+
for (const inlineLabel of inlineNetLabelPlacements) {
|
|
13651
|
+
if (inlineLabel.stubTracePath) {
|
|
13616
13652
|
graphics.lines.push({
|
|
13617
|
-
points:
|
|
13653
|
+
points: inlineLabel.stubTracePath,
|
|
13618
13654
|
strokeColor: "purple"
|
|
13619
13655
|
});
|
|
13620
13656
|
}
|
|
13621
|
-
const
|
|
13622
|
-
|
|
13623
|
-
|
|
13624
|
-
|
|
13625
|
-
|
|
13626
|
-
|
|
13627
|
-
fill: getColorFromString(label.globalConnNetId, 0.35),
|
|
13628
|
-
strokeColor: getColorFromString(label.globalConnNetId, 0.9),
|
|
13629
|
-
label: `netId: ${label.netId}
|
|
13630
|
-
globalConnNetId: ${label.globalConnNetId}`
|
|
13631
|
-
});
|
|
13632
|
-
graphics.points.push({
|
|
13633
|
-
x: label.anchorPoint.x,
|
|
13634
|
-
y: label.anchorPoint.y,
|
|
13635
|
-
color: getColorFromString(label.globalConnNetId, 0.9),
|
|
13636
|
-
label: `anchorPoint
|
|
13637
|
-
orientation: ${label.orientation}`
|
|
13638
|
-
});
|
|
13657
|
+
const isHorizontal4 = inlineLabel.axis === "x";
|
|
13658
|
+
let renderedWidth = inlineLabel.width;
|
|
13659
|
+
let renderedHeight = inlineLabel.height;
|
|
13660
|
+
if (!isHorizontal4) {
|
|
13661
|
+
renderedWidth = inlineLabel.height;
|
|
13662
|
+
renderedHeight = inlineLabel.width;
|
|
13639
13663
|
}
|
|
13640
|
-
|
|
13641
|
-
|
|
13642
|
-
|
|
13643
|
-
|
|
13644
|
-
|
|
13645
|
-
|
|
13664
|
+
graphics.rects.push({
|
|
13665
|
+
center: inlineLabel.center,
|
|
13666
|
+
width: renderedWidth,
|
|
13667
|
+
height: renderedHeight,
|
|
13668
|
+
fill: getColorFromString(inlineLabel.globalConnNetId, 0.35),
|
|
13669
|
+
strokeColor: "green",
|
|
13670
|
+
label: [
|
|
13671
|
+
`INLINE netId: ${inlineLabel.netId}`,
|
|
13672
|
+
`axis: ${inlineLabel.axis}`,
|
|
13673
|
+
`side: ${inlineLabel.side}`
|
|
13674
|
+
].join("\n")
|
|
13675
|
+
});
|
|
13676
|
+
let textX = inlineLabel.center.x;
|
|
13677
|
+
let textY = inlineLabel.center.y;
|
|
13678
|
+
let anchorSide = "center";
|
|
13679
|
+
let rotation;
|
|
13680
|
+
if (inlineLabel.stubTracePath) {
|
|
13681
|
+
const stubStart = inlineLabel.stubTracePath[0];
|
|
13682
|
+
const stubEnd = inlineLabel.stubTracePath[1];
|
|
13683
|
+
let labelOffset = inlineLabel.width / 2;
|
|
13684
|
+
if (stubEnd[inlineLabel.axis] > stubStart[inlineLabel.axis]) {
|
|
13685
|
+
labelOffset = -inlineLabel.width / 2;
|
|
13686
|
+
anchorSide = "center_left";
|
|
13687
|
+
} else {
|
|
13688
|
+
anchorSide = "center_right";
|
|
13689
|
+
}
|
|
13690
|
+
if (inlineLabel.axis === "x") {
|
|
13691
|
+
textX += labelOffset;
|
|
13692
|
+
} else {
|
|
13693
|
+
textY += labelOffset;
|
|
13646
13694
|
}
|
|
13647
|
-
const isHorizontal4 = inlineLabel.axis === "x";
|
|
13648
|
-
graphics.rects.push({
|
|
13649
|
-
center: inlineLabel.center,
|
|
13650
|
-
width: isHorizontal4 ? inlineLabel.width : inlineLabel.height,
|
|
13651
|
-
height: isHorizontal4 ? inlineLabel.height : inlineLabel.width,
|
|
13652
|
-
fill: getColorFromString(inlineLabel.globalConnNetId, 0.35),
|
|
13653
|
-
strokeColor: "green",
|
|
13654
|
-
label: [
|
|
13655
|
-
`INLINE netId: ${inlineLabel.netId}`,
|
|
13656
|
-
`axis: ${inlineLabel.axis}`,
|
|
13657
|
-
`side: ${inlineLabel.side}`
|
|
13658
|
-
].join("\n")
|
|
13659
|
-
});
|
|
13660
|
-
graphics.texts.push({
|
|
13661
|
-
x: inlineLabel.stubTracePath && inlineLabel.axis === "x" ? inlineLabel.center.x + (inlineLabel.stubTracePath[1].x > inlineLabel.stubTracePath[0].x ? -inlineLabel.width / 2 : inlineLabel.width / 2) : inlineLabel.center.x,
|
|
13662
|
-
y: inlineLabel.stubTracePath && inlineLabel.axis === "y" ? inlineLabel.center.y + (inlineLabel.stubTracePath[1].y > inlineLabel.stubTracePath[0].y ? -inlineLabel.width / 2 : inlineLabel.width / 2) : inlineLabel.center.y,
|
|
13663
|
-
text: inlineLabel.netLabelText ?? inlineLabel.netId ?? "",
|
|
13664
|
-
color: "green",
|
|
13665
|
-
fontSize: inlineLabel.height,
|
|
13666
|
-
anchorSide: inlineLabel.stubTracePath ? inlineLabel.stubTracePath[1][inlineLabel.axis] > inlineLabel.stubTracePath[0][inlineLabel.axis] ? "center_left" : "center_right" : "center",
|
|
13667
|
-
// Vertical labels read bottom-to-top, alongside the wire they name.
|
|
13668
|
-
rotation: inlineLabel.axis === "y" ? 90 : void 0
|
|
13669
|
-
});
|
|
13670
|
-
graphics.points.push({
|
|
13671
|
-
x: inlineLabel.anchorPoint.x,
|
|
13672
|
-
y: inlineLabel.anchorPoint.y,
|
|
13673
|
-
color: "green",
|
|
13674
|
-
label: `inline anchor
|
|
13675
|
-
${inlineLabel.netLabelText ?? inlineLabel.netId}`
|
|
13676
|
-
});
|
|
13677
13695
|
}
|
|
13678
|
-
|
|
13696
|
+
if (inlineLabel.axis === "y") rotation = 90;
|
|
13697
|
+
graphics.texts.push({
|
|
13698
|
+
x: textX,
|
|
13699
|
+
y: textY,
|
|
13700
|
+
text: inlineLabel.netLabelText ?? inlineLabel.netId ?? "",
|
|
13701
|
+
color: "green",
|
|
13702
|
+
fontSize: inlineLabel.height,
|
|
13703
|
+
anchorSide,
|
|
13704
|
+
// Vertical labels read bottom-to-top, alongside the wire they name.
|
|
13705
|
+
rotation
|
|
13706
|
+
});
|
|
13707
|
+
graphics.points.push({
|
|
13708
|
+
x: inlineLabel.anchorPoint.x,
|
|
13709
|
+
y: inlineLabel.anchorPoint.y,
|
|
13710
|
+
color: "green",
|
|
13711
|
+
label: `inline anchor
|
|
13712
|
+
${inlineLabel.netLabelText ?? inlineLabel.netId}`
|
|
13713
|
+
});
|
|
13679
13714
|
}
|
|
13715
|
+
return graphics;
|
|
13680
13716
|
};
|
|
13681
13717
|
var estimateInlineNetLabelWidth = (text, fontSize = DEFAULT_INLINE_NET_LABEL_HEIGHT) => {
|
|
13682
13718
|
const fontScale = fontSize / 0.18;
|
|
@@ -13762,6 +13798,250 @@ var getCollisionLimitedTerminalStubEnd = ({
|
|
|
13762
13798
|
return isHorizontal4 ? { x: start.x + direction * availableLength, y: start.y } : { x: start.x, y: start.y + direction * availableLength };
|
|
13763
13799
|
};
|
|
13764
13800
|
|
|
13801
|
+
// lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts
|
|
13802
|
+
import {
|
|
13803
|
+
doesSegmentIntersectRect,
|
|
13804
|
+
getBoundFromCenteredRect
|
|
13805
|
+
} from "@tscircuit/math-utils";
|
|
13806
|
+
|
|
13807
|
+
// lib/solvers/NetLabelTraceRecovery/getTraceRecoveryConnectivityMaps.ts
|
|
13808
|
+
var getTraceRecoveryConnectivityMaps = (inputProblem) => {
|
|
13809
|
+
const chipMap = {};
|
|
13810
|
+
const pinMap = /* @__PURE__ */ new Map();
|
|
13811
|
+
for (const chip of inputProblem.chips) {
|
|
13812
|
+
chipMap[chip.chipId] = chip;
|
|
13813
|
+
for (const pin of chip.pins) {
|
|
13814
|
+
pinMap.set(pin.pinId, {
|
|
13815
|
+
...pin,
|
|
13816
|
+
chipId: chip.chipId,
|
|
13817
|
+
_facingDirection: pin._facingDirection ?? getPinDirection(pin, chip)
|
|
13818
|
+
});
|
|
13819
|
+
}
|
|
13820
|
+
}
|
|
13821
|
+
return { chipMap, pinMap };
|
|
13822
|
+
};
|
|
13823
|
+
|
|
13824
|
+
// lib/solvers/NetLabelToTraceSolver/NetLabelToTraceSolver.ts
|
|
13825
|
+
var AVAILABLE_NET_ORIENTATION_PREFIX = "available-net-orientation-";
|
|
13826
|
+
var RECOVERED_TRACE_PREFIX = "net-label-to-trace-";
|
|
13827
|
+
var getCanonicalPairKey = (firstPinId, secondPinId) => [firstPinId, secondPinId].sort().join("--");
|
|
13828
|
+
var pathIntersectsRenderedLabel = (path, label) => {
|
|
13829
|
+
let width = label.width;
|
|
13830
|
+
let height = label.height;
|
|
13831
|
+
if ("axis" in label && label.axis === "y") {
|
|
13832
|
+
width = label.height;
|
|
13833
|
+
height = label.width;
|
|
13834
|
+
}
|
|
13835
|
+
const bounds = getBoundFromCenteredRect({
|
|
13836
|
+
center: label.center,
|
|
13837
|
+
width,
|
|
13838
|
+
height
|
|
13839
|
+
});
|
|
13840
|
+
for (let pathIndex = 0; pathIndex < path.length - 1; pathIndex++) {
|
|
13841
|
+
if (doesSegmentIntersectRect(path[pathIndex], path[pathIndex + 1], bounds)) {
|
|
13842
|
+
return true;
|
|
13843
|
+
}
|
|
13844
|
+
}
|
|
13845
|
+
return false;
|
|
13846
|
+
};
|
|
13847
|
+
var getPerpendicularOffset = (firstPin, secondPin) => {
|
|
13848
|
+
const xDistance = Math.abs(firstPin.x - secondPin.x);
|
|
13849
|
+
const yDistance = Math.abs(firstPin.y - secondPin.y);
|
|
13850
|
+
if (xDistance >= yDistance) return yDistance;
|
|
13851
|
+
return xDistance;
|
|
13852
|
+
};
|
|
13853
|
+
var NetLabelToTraceSolver = class extends BaseSolver {
|
|
13854
|
+
constructor(input) {
|
|
13855
|
+
super();
|
|
13856
|
+
this.input = input;
|
|
13857
|
+
this.inputProblem = input.inputProblem;
|
|
13858
|
+
this.outputTraces = [...input.traces];
|
|
13859
|
+
this.outputNetLabelPlacements = [...input.netLabelPlacements];
|
|
13860
|
+
const { chipMap, pinMap } = getTraceRecoveryConnectivityMaps(
|
|
13861
|
+
this.inputProblem
|
|
13862
|
+
);
|
|
13863
|
+
this.chipMap = chipMap;
|
|
13864
|
+
this.pinMap = pinMap;
|
|
13865
|
+
this.queuedCandidates = this.buildCandidatePairs();
|
|
13866
|
+
this.stats.candidateCount = this.queuedCandidates.length;
|
|
13867
|
+
this.stats.recoveredTraceCount = 0;
|
|
13868
|
+
}
|
|
13869
|
+
input;
|
|
13870
|
+
inputProblem;
|
|
13871
|
+
outputTraces;
|
|
13872
|
+
outputNetLabelPlacements;
|
|
13873
|
+
chipMap;
|
|
13874
|
+
pinMap;
|
|
13875
|
+
queuedCandidates;
|
|
13876
|
+
currentCandidate = null;
|
|
13877
|
+
getConstructorParams() {
|
|
13878
|
+
return [this.input];
|
|
13879
|
+
}
|
|
13880
|
+
isEligiblePortOnlyDirectConnectionLabel(label, groundGlobalConnNetId) {
|
|
13881
|
+
if (label.pinIds.length !== 1 || label.mspConnectionPairIds.length !== 0 || !label.netId || label.netId === "GND" || label.globalConnNetId === groundGlobalConnNetId) {
|
|
13882
|
+
return false;
|
|
13883
|
+
}
|
|
13884
|
+
const pinId = label.pinIds[0];
|
|
13885
|
+
return this.inputProblem.directConnections.some(
|
|
13886
|
+
(connection) => connection.netId === label.netId && connection.pinIds.includes(pinId)
|
|
13887
|
+
);
|
|
13888
|
+
}
|
|
13889
|
+
buildCandidatePairs() {
|
|
13890
|
+
const { netConnMap } = getConnectivityMapsFromInputProblem(
|
|
13891
|
+
this.inputProblem
|
|
13892
|
+
);
|
|
13893
|
+
const groundGlobalConnNetId = netConnMap.getNetConnectedToId("GND") ?? void 0;
|
|
13894
|
+
const labelsByGlobalNet = /* @__PURE__ */ new Map();
|
|
13895
|
+
for (const label of this.input.netLabelPlacements) {
|
|
13896
|
+
if (!this.isEligiblePortOnlyDirectConnectionLabel(
|
|
13897
|
+
label,
|
|
13898
|
+
groundGlobalConnNetId
|
|
13899
|
+
)) {
|
|
13900
|
+
continue;
|
|
13901
|
+
}
|
|
13902
|
+
const labels = labelsByGlobalNet.get(label.globalConnNetId) ?? [];
|
|
13903
|
+
labels.push(label);
|
|
13904
|
+
labelsByGlobalNet.set(label.globalConnNetId, labels);
|
|
13905
|
+
}
|
|
13906
|
+
const candidates = [];
|
|
13907
|
+
for (const labels of labelsByGlobalNet.values()) {
|
|
13908
|
+
for (let firstIndex = 0; firstIndex < labels.length; firstIndex++) {
|
|
13909
|
+
for (let secondIndex = firstIndex + 1; secondIndex < labels.length; secondIndex++) {
|
|
13910
|
+
const firstLabel = labels[firstIndex];
|
|
13911
|
+
const secondLabel = labels[secondIndex];
|
|
13912
|
+
const firstPin = this.pinMap.get(firstLabel.pinIds[0]);
|
|
13913
|
+
const secondPin = this.pinMap.get(secondLabel.pinIds[0]);
|
|
13914
|
+
if (!firstPin || !secondPin) continue;
|
|
13915
|
+
if (arePinsInDifferentSchematicSections(
|
|
13916
|
+
this.inputProblem,
|
|
13917
|
+
firstPin,
|
|
13918
|
+
secondPin
|
|
13919
|
+
)) {
|
|
13920
|
+
continue;
|
|
13921
|
+
}
|
|
13922
|
+
if (doesPairCrossRestrictedCenterLines({
|
|
13923
|
+
inputProblem: this.inputProblem,
|
|
13924
|
+
chipMap: this.chipMap,
|
|
13925
|
+
pinIdMap: this.pinMap,
|
|
13926
|
+
p1: firstPin,
|
|
13927
|
+
p2: secondPin
|
|
13928
|
+
})) {
|
|
13929
|
+
continue;
|
|
13930
|
+
}
|
|
13931
|
+
candidates.push({
|
|
13932
|
+
firstLabel,
|
|
13933
|
+
secondLabel,
|
|
13934
|
+
pins: [firstPin, secondPin],
|
|
13935
|
+
perpendicularOffset: getPerpendicularOffset(firstPin, secondPin),
|
|
13936
|
+
routeDistance: Math.abs(firstPin.x - secondPin.x) + Math.abs(firstPin.y - secondPin.y),
|
|
13937
|
+
key: getCanonicalPairKey(firstPin.pinId, secondPin.pinId)
|
|
13938
|
+
});
|
|
13939
|
+
}
|
|
13940
|
+
}
|
|
13941
|
+
}
|
|
13942
|
+
candidates.sort(
|
|
13943
|
+
(first, second) => first.perpendicularOffset - second.perpendicularOffset || first.routeDistance - second.routeDistance || first.key.localeCompare(second.key)
|
|
13944
|
+
);
|
|
13945
|
+
return candidates;
|
|
13946
|
+
}
|
|
13947
|
+
isSupersededConnectorTrace(trace, candidate) {
|
|
13948
|
+
if (!trace.mspPairId.startsWith(AVAILABLE_NET_ORIENTATION_PREFIX)) {
|
|
13949
|
+
return false;
|
|
13950
|
+
}
|
|
13951
|
+
if (trace.pinIds.length !== 1) return false;
|
|
13952
|
+
return candidate.pins.some((pin) => pin.pinId === trace.pinIds[0]);
|
|
13953
|
+
}
|
|
13954
|
+
routeIntersectsRemainingLabels(tracePath, candidate) {
|
|
13955
|
+
for (const label of this.outputNetLabelPlacements) {
|
|
13956
|
+
if (label === candidate.firstLabel || label === candidate.secondLabel) {
|
|
13957
|
+
continue;
|
|
13958
|
+
}
|
|
13959
|
+
if (pathIntersectsRenderedLabel(tracePath, label)) return true;
|
|
13960
|
+
}
|
|
13961
|
+
return this.input.inlineNetLabelPlacements.some(
|
|
13962
|
+
(label) => pathIntersectsRenderedLabel(tracePath, label)
|
|
13963
|
+
);
|
|
13964
|
+
}
|
|
13965
|
+
tryAcceptCurrentRoute() {
|
|
13966
|
+
const candidate = this.currentCandidate;
|
|
13967
|
+
const tracePath = this.activeSubSolver?.solvedTracePath;
|
|
13968
|
+
if (!candidate || !tracePath) return;
|
|
13969
|
+
const retainedTraces = this.outputTraces.filter(
|
|
13970
|
+
(trace) => !this.isSupersededConnectorTrace(trace, candidate)
|
|
13971
|
+
);
|
|
13972
|
+
if (doesTraceOverlapWithExistingTraces(tracePath, retainedTraces) || this.routeIntersectsRemainingLabels(tracePath, candidate)) {
|
|
13973
|
+
return;
|
|
13974
|
+
}
|
|
13975
|
+
const [firstPin, secondPin] = candidate.pins;
|
|
13976
|
+
const mspPairId = `${RECOVERED_TRACE_PREFIX}${candidate.key}`;
|
|
13977
|
+
const recoveredTrace = {
|
|
13978
|
+
mspPairId,
|
|
13979
|
+
dcConnNetId: candidate.firstLabel.globalConnNetId,
|
|
13980
|
+
globalConnNetId: candidate.firstLabel.globalConnNetId,
|
|
13981
|
+
pins: [firstPin, secondPin],
|
|
13982
|
+
tracePath,
|
|
13983
|
+
mspConnectionPairIds: [mspPairId],
|
|
13984
|
+
pinIds: [firstPin.pinId, secondPin.pinId]
|
|
13985
|
+
};
|
|
13986
|
+
this.outputTraces = [...retainedTraces, recoveredTrace];
|
|
13987
|
+
this.outputNetLabelPlacements = this.outputNetLabelPlacements.filter(
|
|
13988
|
+
(label) => label !== candidate.firstLabel && label !== candidate.secondLabel
|
|
13989
|
+
);
|
|
13990
|
+
this.stats.recoveredTraceCount++;
|
|
13991
|
+
}
|
|
13992
|
+
_step() {
|
|
13993
|
+
if (this.activeSubSolver) {
|
|
13994
|
+
this.activeSubSolver.step();
|
|
13995
|
+
if (this.activeSubSolver.solved) {
|
|
13996
|
+
this.tryAcceptCurrentRoute();
|
|
13997
|
+
this.activeSubSolver = null;
|
|
13998
|
+
this.currentCandidate = null;
|
|
13999
|
+
} else if (this.activeSubSolver.failed) {
|
|
14000
|
+
this.activeSubSolver = null;
|
|
14001
|
+
this.currentCandidate = null;
|
|
14002
|
+
}
|
|
14003
|
+
return;
|
|
14004
|
+
}
|
|
14005
|
+
let candidate = this.queuedCandidates.shift();
|
|
14006
|
+
while (candidate && (!this.outputNetLabelPlacements.includes(candidate.firstLabel) || !this.outputNetLabelPlacements.includes(candidate.secondLabel))) {
|
|
14007
|
+
candidate = this.queuedCandidates.shift();
|
|
14008
|
+
}
|
|
14009
|
+
if (!candidate) {
|
|
14010
|
+
this.solved = true;
|
|
14011
|
+
return;
|
|
14012
|
+
}
|
|
14013
|
+
this.currentCandidate = candidate;
|
|
14014
|
+
this.activeSubSolver = new SchematicTraceSingleLineSolver2({
|
|
14015
|
+
inputProblem: this.inputProblem,
|
|
14016
|
+
pins: candidate.pins,
|
|
14017
|
+
chipMap: this.chipMap
|
|
14018
|
+
});
|
|
14019
|
+
}
|
|
14020
|
+
getOutput() {
|
|
14021
|
+
return {
|
|
14022
|
+
traces: this.outputTraces,
|
|
14023
|
+
netLabelPlacements: this.outputNetLabelPlacements,
|
|
14024
|
+
inlineNetLabelPlacements: this.input.inlineNetLabelPlacements
|
|
14025
|
+
};
|
|
14026
|
+
}
|
|
14027
|
+
visualize() {
|
|
14028
|
+
if (this.activeSubSolver) return this.activeSubSolver.visualize();
|
|
14029
|
+
const graphics = visualizeInlineNetLabelOutput({
|
|
14030
|
+
inputProblem: this.inputProblem,
|
|
14031
|
+
...this.getOutput()
|
|
14032
|
+
});
|
|
14033
|
+
for (const trace of this.outputTraces) {
|
|
14034
|
+
if (!trace.mspPairId.startsWith(RECOVERED_TRACE_PREFIX)) continue;
|
|
14035
|
+
graphics.lines.push({
|
|
14036
|
+
points: trace.tracePath,
|
|
14037
|
+
strokeColor: "green",
|
|
14038
|
+
label: `recovered from net labels: ${trace.pinIds.join(" -> ")}`
|
|
14039
|
+
});
|
|
14040
|
+
}
|
|
14041
|
+
return graphics;
|
|
14042
|
+
}
|
|
14043
|
+
};
|
|
14044
|
+
|
|
13765
14045
|
// lib/solvers/SchematicTracePipelineSolver/SchematicTracePipelineSolver.ts
|
|
13766
14046
|
function definePipelineStep(solverName, solverClass, getConstructorParams, opts = {}) {
|
|
13767
14047
|
return {
|
|
@@ -13800,6 +14080,7 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
13800
14080
|
finalTraceElbowTransitionSimplificationSolver;
|
|
13801
14081
|
sameNetJunctionAlignmentSolver;
|
|
13802
14082
|
inlineNetLabelSolver;
|
|
14083
|
+
netLabelToTraceSolver;
|
|
13803
14084
|
startTimeOfPhase;
|
|
13804
14085
|
endTimeOfPhase;
|
|
13805
14086
|
timeSpentOnPhase;
|
|
@@ -14211,6 +14492,19 @@ var SchematicTracePipelineSolver = class extends BaseSolver {
|
|
|
14211
14492
|
}
|
|
14212
14493
|
];
|
|
14213
14494
|
}
|
|
14495
|
+
),
|
|
14496
|
+
definePipelineStep(
|
|
14497
|
+
"netLabelToTraceSolver",
|
|
14498
|
+
NetLabelToTraceSolver,
|
|
14499
|
+
(instance) => {
|
|
14500
|
+
const inlineOutput = instance.inlineNetLabelSolver.getOutput();
|
|
14501
|
+
return [
|
|
14502
|
+
{
|
|
14503
|
+
inputProblem: instance.inputProblem,
|
|
14504
|
+
...inlineOutput
|
|
14505
|
+
}
|
|
14506
|
+
];
|
|
14507
|
+
}
|
|
14214
14508
|
)
|
|
14215
14509
|
];
|
|
14216
14510
|
constructor(inputProblem, opts) {
|
|
@@ -14331,5 +14625,6 @@ export {
|
|
|
14331
14625
|
InlineNetLabelSolver,
|
|
14332
14626
|
SchematicTracePipelineSolver,
|
|
14333
14627
|
SchematicTraceSingleLineSolver2,
|
|
14334
|
-
estimateInlineNetLabelWidth
|
|
14628
|
+
estimateInlineNetLabelWidth,
|
|
14629
|
+
visualizeInlineNetLabelOutput
|
|
14335
14630
|
};
|